diff --git a/packages/iceworks-client/package.json b/packages/iceworks-client/package.json index c13c2c0297..3023bbf33f 100644 --- a/packages/iceworks-client/package.json +++ b/packages/iceworks-client/package.json @@ -6,10 +6,11 @@ "@alifd/next": "^1.13.13", "@alifd/theme-2": "^0.0.22", "@alifd/theme-3": "^0.1.0", + "@icedesign/notification": "^1.0.5", "alife-logger": "^1.5.1", "classnames": "^2.2.6", + "cookies-js": "^1.2.3", "deepmerge": "^3.2.0", - "iceworks-events": "^0.1.0", "icestore": "^0.1.0", "lodash.map": "^4.6.0", "loglevel": "^1.6.1", diff --git a/packages/iceworks-client/public/index.html b/packages/iceworks-client/public/index.html index 246ae1afd3..4d4e464c03 100644 --- a/packages/iceworks-client/public/index.html +++ b/packages/iceworks-client/public/index.html @@ -10,5 +10,11 @@
+ diff --git a/packages/iceworks-client/src/components/ConnectionBar/index.js b/packages/iceworks-client/src/components/ConnectionBar/index.js deleted file mode 100644 index 4d67440c38..0000000000 --- a/packages/iceworks-client/src/components/ConnectionBar/index.js +++ /dev/null @@ -1,25 +0,0 @@ -import React from 'react'; -import { FormattedMessage } from 'react-intl'; -import { Context as SocketContext } from '@hooks/useSocket'; -import styles from './index.module.scss'; - -const ConnectionBar = () => { - return ( - - {value => ( -
- {value[1] ? ( - - ) : ( - - )} -
- )} -
- ); -}; - -ConnectionBar.propTypes = { -}; - -export default ConnectionBar; diff --git a/packages/iceworks-client/src/components/ConnectionBar/index.module.scss b/packages/iceworks-client/src/components/ConnectionBar/index.module.scss deleted file mode 100644 index 3c17e7f6c4..0000000000 --- a/packages/iceworks-client/src/components/ConnectionBar/index.module.scss +++ /dev/null @@ -1,11 +0,0 @@ -@import '../../variables.scss'; - -.connectionBar { - flex: auto 0 0; - height: 40px; - background: $warning-color; - color: $white; - display: flex; - align-items: center; - justify-content: center; -} diff --git a/packages/iceworks-client/src/components/GlobalBar/index.js b/packages/iceworks-client/src/components/GlobalBar/index.js index 04820e2b3b..d2a7ef5feb 100644 --- a/packages/iceworks-client/src/components/GlobalBar/index.js +++ b/packages/iceworks-client/src/components/GlobalBar/index.js @@ -1,8 +1,19 @@ -import React from 'react'; +import React, { useEffect } from 'react'; +import stores from '@stores'; import styles from './index.module.scss'; const GlobalBar = () => { - return
Global Bar
; + const project = stores.useStore('project'); + + useEffect(() => { + project.refresh(); + }, []); + + return ( +
+ {project.dataSource.name} +
+ ); }; export default GlobalBar; diff --git a/packages/iceworks-client/src/components/XtermTerminal/index.js b/packages/iceworks-client/src/components/XtermTerminal/index.js index 3b92386ee5..baee8bf95f 100644 --- a/packages/iceworks-client/src/components/XtermTerminal/index.js +++ b/packages/iceworks-client/src/components/XtermTerminal/index.js @@ -1,18 +1,22 @@ import React, { useRef, useEffect } from 'react'; // import PropTypes from 'prop-types'; import { Terminal } from 'xterm'; -import { ICEWORKS_TASK_DEV_DATA } from 'iceworks-events'; -import { useSocket } from '@hooks/useSocket'; +import useSocket from '@hooks/useSocket'; import * as fit from 'xterm/dist/addons/fit/fit'; import * as webLinks from 'xterm/dist/addons/webLinks/webLinks'; +import stores from '@stores'; import 'xterm/dist/xterm.css'; +import log from '@utils/logger'; import styles from './index.module.scss'; +const logger = log.getLogger('xterm'); + Terminal.applyAddon(fit); Terminal.applyAddon(webLinks); const XtermTerminal = () => { const xtermRef = useRef(null); + const project = stores.useStore('project'); const term = new Terminal({ cols: 100, @@ -20,12 +24,16 @@ const XtermTerminal = () => { }); useEffect(() => { + logger.debug('xterm loaded.'); + + project.refresh(); + term.open(xtermRef.current); term.fit(); - term.write('\x1B[1;3;31mIceworks CLI\x1B[0m $ '); + term.write(`\x1B[1;3;31m${project.dataSource.name}\x1B[0m $ `); }, []); - useSocket(ICEWORKS_TASK_DEV_DATA, (data) => { + useSocket('project.index.dev.data', (data) => { term.write(data); }); diff --git a/packages/iceworks-client/src/hooks/useSocket/useSocket.js b/packages/iceworks-client/src/hooks/useSocket.js similarity index 67% rename from packages/iceworks-client/src/hooks/useSocket/useSocket.js rename to packages/iceworks-client/src/hooks/useSocket.js index bfee22a1fd..67fe7bfd97 100644 --- a/packages/iceworks-client/src/hooks/useSocket/useSocket.js +++ b/packages/iceworks-client/src/hooks/useSocket.js @@ -1,11 +1,9 @@ /* eslint consistent-return:0 */ -import { useContext, useEffect } from 'react'; +import { useEffect } from 'react'; import logger from '@utils/logger'; -import Context from './Context'; - -function useSocket(eventName, callback) { - const [socket] = useContext(Context); +import socket from '@src/socket'; +export default function useSocket(eventName, callback) { useEffect(() => { if (eventName && callback) { logger.debug(`socket on ${eventName}.`); @@ -20,5 +18,3 @@ function useSocket(eventName, callback) { return socket; } - -export default useSocket; diff --git a/packages/iceworks-client/src/hooks/useSocket/Context.js b/packages/iceworks-client/src/hooks/useSocket/Context.js deleted file mode 100644 index 4493bee34e..0000000000 --- a/packages/iceworks-client/src/hooks/useSocket/Context.js +++ /dev/null @@ -1,5 +0,0 @@ -import { createContext } from 'react'; - -const Context = createContext(); - -export default Context; diff --git a/packages/iceworks-client/src/hooks/useSocket/SocketProvider.js b/packages/iceworks-client/src/hooks/useSocket/SocketProvider.js deleted file mode 100644 index 2837cd6946..0000000000 --- a/packages/iceworks-client/src/hooks/useSocket/SocketProvider.js +++ /dev/null @@ -1,39 +0,0 @@ -import React, { useState } from 'react'; -import PropTypes from 'prop-types'; -import io from 'socket.io-client'; -import logger from '@utils/logger'; -import Context from './Context'; - -let didConnect = false; - -const SocketProvider = ({ children, url, options }) => { - const [connect, setConect] = useState(false); - const socket = io(url, options); - - if (!didConnect) { - socket.on('connect', () => { - logger.debug('socket connect!!!'); - didConnect = true; - setConect(true); - }); - socket.on('disconnect', () => { - logger.debug('socket disconnect!!!'); - didConnect = false; - setConect(true); - }); - } - - return {children}; -}; - -SocketProvider.defaultProps = { - options: {}, -}; - -SocketProvider.propTypes = { - children: PropTypes.node.isRequired, - url: PropTypes.string.isRequired, - options: PropTypes.object, -}; - -export default SocketProvider; diff --git a/packages/iceworks-client/src/hooks/useSocket/index.js b/packages/iceworks-client/src/hooks/useSocket/index.js deleted file mode 100644 index e014bae23b..0000000000 --- a/packages/iceworks-client/src/hooks/useSocket/index.js +++ /dev/null @@ -1,5 +0,0 @@ -import SocketProvider from './SocketProvider'; -import useSocket from './useSocket'; -import Context from './Context'; - -export { SocketProvider, useSocket, Context }; diff --git a/packages/iceworks-client/src/index.js b/packages/iceworks-client/src/index.js index 9a80985050..c2b37b192c 100644 --- a/packages/iceworks-client/src/index.js +++ b/packages/iceworks-client/src/index.js @@ -1,31 +1,28 @@ -import React from 'react'; +import React, { useEffect } from 'react'; import ReactDOM from 'react-dom'; import { BrowserRouter as Router, Route } from 'react-router-dom'; -import '@utils/logger'; import '@alifd/next/reset.scss'; +import logger from '@utils/logger'; import MainLayout from '@layouts/MainLayout/index'; import LocaleProvider from '@components/Locale'; import { ThemeProvider } from '@components/ThemeProvider'; -import { SocketProvider } from '@hooks/useSocket'; -import appConfig from './appConfig'; - import './global.scss'; import './variables.scss'; -const URL = appConfig.socketUrl; - const App = () => { + useEffect(() => { + logger.info('App loaded.'); + }, []); + return ( - - - - - - - - - + + + + + + + ); }; diff --git a/packages/iceworks-client/src/layouts/MainLayout/index.js b/packages/iceworks-client/src/layouts/MainLayout/index.js index 2897c33501..6d8ede3efa 100644 --- a/packages/iceworks-client/src/layouts/MainLayout/index.js +++ b/packages/iceworks-client/src/layouts/MainLayout/index.js @@ -1,7 +1,6 @@ import React from 'react'; import NavigationBar from '@components/NavigationBar'; import RouteRender from '@components/RouteRender'; -import ConnectionBar from '@components/ConnectionBar'; import GlobalBar from '@components/GlobalBar'; import menuConfig from '@src/menuConfig'; import routerConfig from '@src/routerConfig'; @@ -10,7 +9,6 @@ import styles from './index.module.scss'; const MainLayout = () => { return (
-
diff --git a/packages/iceworks-client/src/pages/Dev/index.js b/packages/iceworks-client/src/pages/Dev/index.js index 7f02850512..894865af71 100644 --- a/packages/iceworks-client/src/pages/Dev/index.js +++ b/packages/iceworks-client/src/pages/Dev/index.js @@ -1,26 +1,38 @@ import React from 'react'; import { Button } from '@alifd/next'; -import { - ICEWORKS_TASK_DEV_OPEN, - ICEWORKS_TASK_DEV_DATA, -} from 'iceworks-events'; import Card from '@components/Card'; import Icon from '@components/Icon'; import Modal from '@components/Modal'; import XtermTerminal from '@components/XtermTerminal'; import useModal from '@hooks/useModal'; -import { useSocket } from '@hooks/useSocket'; -import logger from '@utils/logger'; +import stores from '@stores'; +import IceNotification from '@icedesign/notification'; import styles from './index.module.scss'; const Dev = () => { + const project = stores.useStore('project'); const { on, toggleModal } = useModal(); - const socket = useSocket(ICEWORKS_TASK_DEV_DATA, (data) => { - logger.debug(ICEWORKS_TASK_DEV_DATA, data); - }); - const dev = () => { - socket.emit(ICEWORKS_TASK_DEV_OPEN, 'dev'); + const devStart = async () => { + try { + await project.devStart(); + } catch (error) { + IceNotification.error({ + message: '启动调试服务失败', + description: error.message || '当前项目依赖未安装或依赖缺失,请重装依赖后重试。', + }); + } + }; + + const devStop = async () => { + try { + await project.devStop(); + } catch (error) { + IceNotification.error({ + message: '终止调试服务失败', + description: error.message || '请重试。', + }); + } }; return ( @@ -33,10 +45,17 @@ const Dev = () => {
{/* Left Button Group */}
- + { + project.dataSource.devStatus !== 'working' ? + : + + }
-
-
my materials
-
    - {materials.dataSource.map(({ name }, index) => { - return
  • {name}
  • ; - })} -
-
); }; diff --git a/packages/iceworks-client/src/pages/Project/stores/dependencies.js b/packages/iceworks-client/src/pages/Project/stores/dependencies.js new file mode 100644 index 0000000000..98908ebb6f --- /dev/null +++ b/packages/iceworks-client/src/pages/Project/stores/dependencies.js @@ -0,0 +1,19 @@ +import socket from '@src/socket'; + +export default { + dataSource: [], + inited: false, + async refresh(projectFolderPath) { + if (this.inited) { + return; + } + + try { + const dataSource = await socket.emit('project.dependency.list', { projectFolderPath }); + this.dataSource = dataSource; + this.inited = true; + } catch (error) { + // do something... + } + }, +}; diff --git a/packages/iceworks-client/src/pages/Project/stores/index.js b/packages/iceworks-client/src/pages/Project/stores/index.js new file mode 100644 index 0000000000..a5e95982f4 --- /dev/null +++ b/packages/iceworks-client/src/pages/Project/stores/index.js @@ -0,0 +1,9 @@ +import Icestore from 'icestore'; +import pages from './pages'; +import dependencies from './dependencies'; + +const icestore = new Icestore(); +icestore.registerStore('pages', pages); +icestore.registerStore('dependencies', dependencies); + +export default icestore; diff --git a/packages/iceworks-client/src/pages/Project/stores/pages.js b/packages/iceworks-client/src/pages/Project/stores/pages.js new file mode 100644 index 0000000000..4f3e1ba179 --- /dev/null +++ b/packages/iceworks-client/src/pages/Project/stores/pages.js @@ -0,0 +1,19 @@ +import socket from '@src/socket'; + +export default { + dataSource: [], + inited: false, + async refresh(projectFolderPath) { + if (this.inited) { + return; + } + + try { + const dataSource = await socket.emit('project.page.list', { projectFolderPath }); + this.dataSource = dataSource; + this.inited = true; + } catch (error) { + // do something... + } + }, +}; diff --git a/packages/iceworks-client/src/socket.js b/packages/iceworks-client/src/socket.js new file mode 100644 index 0000000000..3be403c9bb --- /dev/null +++ b/packages/iceworks-client/src/socket.js @@ -0,0 +1,34 @@ + +import io from 'socket.io-client'; +import logger from '@utils/logger'; +import appConfig from './appConfig'; + +const socket = io(appConfig.socketUrl); + +socket.on('connect', () => { + logger.debug('socket connected!!!'); +}); +socket.on('disconnect', () => { + logger.debug('socket disconnected!!!'); +}); + +const originalEmit = socket.emit.bind(socket); +socket.emit = function emit(...args) { + return new Promise((resolve, reject) => { + if (!args[1]) { + args.push({}); + } + + args.push(({ error, data }) => { + if (error) { + reject(error); + } else { + resolve(data); + } + }); + + originalEmit(...args); + }); +}; + +export default socket; diff --git a/packages/iceworks-client/src/stores/currentProject.js b/packages/iceworks-client/src/stores/currentProject.js index f22a4188f8..26eb0cabfe 100644 --- a/packages/iceworks-client/src/stores/currentProject.js +++ b/packages/iceworks-client/src/stores/currentProject.js @@ -1,28 +1,25 @@ -import logger from '@utils/logger'; +import socket from '@src/socket'; export default { dataSource: { id: '0', - name: 'projectA', + name: '', pages: [ ], }, + inited: false, async refresh() { - await new Promise(resolve => setTimeout(() => { - logger.debug('fetched project!!!'); - resolve(); - }, 1000)); + if (this.inited) { + return; + } - this.dataSource = { - id: '0', - name: 'projectA', - pages: [ - { - id: '0', - name: 'pageA', - }, - ], - }; + try { + const dataSource = await socket.emit('project.index.current'); + this.dataSource = dataSource; + this.inited = true; + } catch (error) { + // do something... + } }, async addPage(page) { await new Promise(resolve => setTimeout(resolve, 1000)); @@ -30,8 +27,26 @@ export default { const { pages } = this.dataSource; this.pages = [].concat(pages).concat([{ ...page, id: pages.length }]); }, - async setData(project) { - await new Promise(resolve => setTimeout(resolve, 1000)); - this.dataSource = project; + async reset(folderPath) { + try { + const dataSource = await socket.emit('project.index.setCurrent', { folderPath }); + this.dataSource = dataSource; + } catch (error) { + // do something... + } + }, + async devStart() { + const dataSource = await socket.emit( + 'project.index.devStart', + { projectFolderPath: this.dataSource.folderPath }, + ); + this.dataSource = dataSource; + }, + async devStop() { + const dataSource = await socket.emit( + 'project.index.devStop', + { projectFolderPath: this.dataSource.folderPath }, + ); + this.dataSource = dataSource; }, }; diff --git a/packages/iceworks-client/src/stores/projects.js b/packages/iceworks-client/src/stores/projects.js index 7ee9f878f0..9ad2b41158 100644 --- a/packages/iceworks-client/src/stores/projects.js +++ b/packages/iceworks-client/src/stores/projects.js @@ -1,26 +1,20 @@ -import logger from '@utils/logger'; +import socket from '@src/socket'; export default { + inited: false, dataSource: [], async refresh() { - await new Promise(resolve => setTimeout(() => { - logger.debug('fetched projects.'); - resolve(); - }, 1000)); - this.dataSource = [ - { - id: '0', - name: 'projectA', - }, - { - id: '1', - name: 'projectB', - }, - { - id: '2', - name: 'projectC', - }, - ]; + if (this.inited) { + return; + } + + try { + const dataSource = await socket.emit('project.index.list'); + this.dataSource = dataSource; + this.inited = true; + } catch (error) { + // do something... + } }, add(project) { const { dataSource } = this; diff --git a/packages/iceworks-events/README.md b/packages/iceworks-events/README.md deleted file mode 100644 index dfd0caa869..0000000000 --- a/packages/iceworks-events/README.md +++ /dev/null @@ -1,18 +0,0 @@ -## Iceworks Events - -iceworks 的事件定义,统一规范输出相关事件 - -## 使用 - -```js -import emitter from 'xxx-emitter'; -import { ICEWORKS_TASK_DEV_DATA } from 'iceworks-events'; - -setTimeout(function() { - emitter.emit(ICEWORKS_TASK_DEV_OPEN, { id: '1' }); -}, 3000); - -emitter.on(ICEWORKS_TASK_DEV_DATA, (data) => { - console.log(ICEWORKS_TASK_DEV_DATA, data); -}); -``` diff --git a/packages/iceworks-events/lib/index.js b/packages/iceworks-events/lib/index.js deleted file mode 100644 index d1a844b847..0000000000 --- a/packages/iceworks-events/lib/index.js +++ /dev/null @@ -1,3 +0,0 @@ -const tasks = require('./tasks'); - -module.exports = { ...tasks }; diff --git a/packages/iceworks-events/lib/tasks.js b/packages/iceworks-events/lib/tasks.js deleted file mode 100644 index 54d3566f67..0000000000 --- a/packages/iceworks-events/lib/tasks.js +++ /dev/null @@ -1,16 +0,0 @@ -// iceworks events -module.exports = { - /** - * 工程任务监听事件定义 - */ - ICEWORKS_TASK_DEV_DATA: 'ICEWORKS_TASK_DEV_DATA', // 启动 dev 数据流 - ICEWORKS_TASK_BUILD_DATA: 'ICEWORKS_TASK_BUILD_DATA', // 构建 build 数据流 - ICEWORKS_TASK_LINT_DATA: 'ICEWORKS_TASK_LINT_DATA', // 检查 lint 数据流 - - /** - * 工程任务发出事件定义 - */ - ICEWORKS_TASK_DEV_OPEN: 'ICEWORKS_TASK_DEV_OPEN', // 启动 dev 命令 - ICEWORKS_TASK_BUILD_OPEN: 'ICEWORKS_TASK_BUILD_OPEN', // 构建 build 命令 - ICEWORKS_TASK_LINT_OPEN: 'ICEWORKS_TASK_LINT_OPEN', // 检查 lint 命令 -}; diff --git a/packages/iceworks-events/package.json b/packages/iceworks-events/package.json deleted file mode 100644 index 8a3af02e64..0000000000 --- a/packages/iceworks-events/package.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "name": "iceworks-events", - "version": "0.1.1", - "description": "iceworks events", - "main": "lib/index.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "author": "chenbin92", - "license": "MIT" -} diff --git a/packages/iceworks-server/.gitignore b/packages/iceworks-server/.gitignore index ddc80f3873..8fe03d3416 100644 --- a/packages/iceworks-server/.gitignore +++ b/packages/iceworks-server/.gitignore @@ -11,4 +11,6 @@ run/ *.sw* *.un~ .nodejs-cache -src/tms/ \ No newline at end of file +src/tms/ +data/ +dist/ \ No newline at end of file diff --git a/packages/iceworks-server/package.json b/packages/iceworks-server/package.json index 531a7d5b4e..c8d8f35dad 100644 --- a/packages/iceworks-server/package.json +++ b/packages/iceworks-server/package.json @@ -4,13 +4,17 @@ "description": "iceworks server", "private": true, "dependencies": { + "conf": "^4.0.1", + "detect-port": "^1.3.0", + "egg-cors": "^2.2.0", "egg-scripts": "^2.10.0", "egg-socket.io": "^4.1.5", - "execa": "^1.0.0", "egg-view": "^2.1.2", "egg-view-nunjucks": "^2.2.0", - "iceworks-events": "^0.1.0", - "midway": "^1.0.0" + "junk": "^3.1.0", + "midway": "^1.0.0", + "mkdirp": "^0.5.1", + "npm-run-path": "^3.1.0" }, "devDependencies": { "@types/mocha": "^5.2.5", @@ -35,7 +39,8 @@ "debug": "NODE_ENV=local midway-bin debug --ts", "test": "npm run lint && midway-bin test --ts", "cov": "midway-bin cov --ts", - "lint": "tslint -c tslint.json --project .", + "lint": "tslint --fix -c tslint.json --project .", + "lint-nofix": "tslint -c tslint.json --project .", "ci": "npm run cov", "build": "midway-bin build -c" }, diff --git a/packages/iceworks-server/src/app/controller/home.ts b/packages/iceworks-server/src/app/controller/home.ts index f27eeac57a..4772465a5d 100644 --- a/packages/iceworks-server/src/app/controller/home.ts +++ b/packages/iceworks-server/src/app/controller/home.ts @@ -3,7 +3,8 @@ import { controller, get, provide } from 'midway'; @provide() @controller('/') export class HomeController { - @get('/') + + @get('*') async render(ctx) { await ctx.render('index.html', ctx.clientConfig); } diff --git a/packages/iceworks-server/src/app/controller/user.ts b/packages/iceworks-server/src/app/controller/user.ts deleted file mode 100644 index f15a2b55b8..0000000000 --- a/packages/iceworks-server/src/app/controller/user.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { controller, get, inject, provide } from 'midway'; -import { IUserService, IUserResult } from '../../interface'; - -@provide() -@controller('/user') -export class UserController { - @inject('userService') - service: IUserService; - - @get('/:id') - async getUser(ctx): Promise { - const id: number = ctx.params.id; - const user: IUserResult = await this.service.getUser({ id }); - ctx.body = { success: true, message: 'OK', data: user }; - } -} diff --git a/packages/iceworks-server/src/app/io/controller/project/dependency.ts b/packages/iceworks-server/src/app/io/controller/project/dependency.ts new file mode 100644 index 0000000000..4968a901a3 --- /dev/null +++ b/packages/iceworks-server/src/app/io/controller/project/dependency.ts @@ -0,0 +1,26 @@ +export default (app) => { + const { Controller } = app; + + return class DependencyController extends Controller { + async list(ctx) { + const { args } = ctx; + const { projectFolderPath } = args[0]; + const callback = args[args.length - 1]; + + let dependencies = []; + let error; + const dependencyService = await ctx.requestContext.getAsync('dependencyService'); + + try { + dependencies = await dependencyService.getAll(projectFolderPath); + } catch (err) { + error = err; + } + + callback({ + error, + data: dependencies + }); + } + }; +}; diff --git a/packages/iceworks-server/src/app/io/controller/project/index.ts b/packages/iceworks-server/src/app/io/controller/project/index.ts new file mode 100644 index 0000000000..68e1bb2132 --- /dev/null +++ b/packages/iceworks-server/src/app/io/controller/project/index.ts @@ -0,0 +1,124 @@ +import { StringDecoder } from 'string_decoder'; + +export default (app) => { + const { Controller } = app; + + return class ProjectController extends Controller { + async devStart(ctx) { + const { projectManager } = app; + const { args, socket } = ctx; + const { projectFolderPath } = args[0]; + const callback = args[args.length - 1]; + + let error; + let project; + try { + project = await projectManager.devStart(projectFolderPath); + } catch (err) { + error = err; + } + + console.log(error); + + if (project) { + project.on('dev.data', function(data) { + const decoder = new StringDecoder('utf8'); + socket.emit('project.index.dev.data', decoder.write(data)); + }); + } + + callback({ + error, + data: project + }); + } + + async devStop(ctx) { + const { projectManager } = app; + const { args, socket } = ctx; + const { projectFolderPath } = args[0]; + const callback = args[args.length - 1]; + + let error; + let project; + try { + project = await projectManager.devStop(projectFolderPath); + } catch (err) { + error = err; + } + + socket.emit('project.dev.data', '\n\r已中止调试服务\n\r'); + + callback({ + error, + data: project + }); + } + + async list(ctx) { + const { projectManager } = app; + const { args } = ctx; + const callback = args[args.length - 1]; + + let projects = []; + let error; + try { + projects = await projectManager.getProjects(); + } catch (err) { + error = err; + } + + callback({ + error, + data: projects + }); + } + + async getCurrent(ctx) { + const { projectManager } = app; + const { args } = ctx; + const callback = args[args.length - 1]; + + let project = []; + let error; + try { + project = await projectManager.getCurrent(); + } catch (err) { + error = err; + } + + callback({ + error, + data: project + }); + } + + async setCurrent(ctx) { + const { projectManager } = app; + const { args } = ctx; + const { folderPath } = args[0]; + const callback = args[args.length - 1]; + + let project = []; + let error; + try { + project = await projectManager.setCurrent(folderPath); + } catch (err) { + error = err; + } + + callback({ + error, + data: project + }); + } + + async build() { + + } + + async lint() { + + } + }; +}; diff --git a/packages/iceworks-server/src/app/io/controller/project/page.ts b/packages/iceworks-server/src/app/io/controller/project/page.ts new file mode 100644 index 0000000000..a19e018463 --- /dev/null +++ b/packages/iceworks-server/src/app/io/controller/project/page.ts @@ -0,0 +1,26 @@ +export default (app) => { + const { Controller } = app; + + return class PageController extends Controller { + async list(ctx) { + const { args } = ctx; + const { projectFolderPath } = args[0]; + const callback = args[args.length - 1]; + + let pages = []; + let error; + const pageService = await ctx.requestContext.getAsync('pageService'); + + try { + pages = await pageService.getAll(projectFolderPath); + } catch (err) { + error = err; + } + + callback({ + error, + data: pages + }); + } + }; +}; diff --git a/packages/iceworks-server/src/app/io/controller/tasks.ts b/packages/iceworks-server/src/app/io/controller/tasks.ts deleted file mode 100644 index 78eb910e23..0000000000 --- a/packages/iceworks-server/src/app/io/controller/tasks.ts +++ /dev/null @@ -1,23 +0,0 @@ -const { ICEWORKS_TASK_DEV_DATA } = require('iceworks-events'); - -export default (app) => { - return class TasksController extends app.Controller { - async dev(ctx) { - const { args, socket, logger } = ctx; - const taskName = args[0]; - - logger.info('[receive client message]:', taskName + ' : ' + process.pid); - - const tasksService = await ctx.requestContext.getAsync('tasksService'); - const result = await tasksService.dev(); - - if (result.code === 0) { - socket.emit(ICEWORKS_TASK_DEV_DATA, result.stdout); - } - } - - async build() {} - - async lint() {} - }; -}; diff --git a/packages/iceworks-server/src/app/io/service/tasks.ts b/packages/iceworks-server/src/app/io/service/tasks.ts deleted file mode 100644 index 96e8e1a9d4..0000000000 --- a/packages/iceworks-server/src/app/io/service/tasks.ts +++ /dev/null @@ -1,20 +0,0 @@ -const execa = require('execa'); -import { provide, inject } from 'midway'; - -@provide() -export class TasksService { - @inject() - ctx; - - async dev() { - try { - return await execa.shell('npm -v'); - } catch (error) { - return { error }; - } - } - - async build() {} - - async lint() {} -} diff --git a/packages/iceworks-server/src/app/middleware/client.ts b/packages/iceworks-server/src/app/middleware/client.ts index fd04814feb..01a1b43504 100644 --- a/packages/iceworks-server/src/app/middleware/client.ts +++ b/packages/iceworks-server/src/app/middleware/client.ts @@ -1,16 +1,17 @@ export default function() { - return async function client(ctx, next) { - if (String(ctx.path).indexOf('/api') === 0) { - await next(); - return; - } + return async function client(ctx, next) { + if (String(ctx.path).indexOf('/api') === 0) { + await next(); + return; + } - ctx.clientConfig = { - // TODO //unpkg.com/iceworks-client@1.0.0-beta.0/build/ - clientPath: '//127.0.0.1:4444/', - socketUrl: '//127.0.0.1:7001', - }; - - await next(); + ctx.clientConfig = { + // TODO //unpkg.com/iceworks-client@1.0.0-beta.0/build/ + clientPath: '//127.0.0.1:4444/', + socketUrl: '//127.0.0.1:7001/', + apiUrl: '//127.0.0.1:7001/api/' }; + + await next(); + }; } diff --git a/packages/iceworks-server/src/app/public/README.md b/packages/iceworks-server/src/app/public/README.md deleted file mode 100644 index eda21ab1c7..0000000000 --- a/packages/iceworks-server/src/app/public/README.md +++ /dev/null @@ -1 +0,0 @@ -## public static file directory! \ No newline at end of file diff --git a/packages/iceworks-server/src/app/router.ts b/packages/iceworks-server/src/app/router.ts index d513922ee6..e3d8ad8389 100644 --- a/packages/iceworks-server/src/app/router.ts +++ b/packages/iceworks-server/src/app/router.ts @@ -1,5 +1,12 @@ -const { ICEWORKS_TASK_DEV_OPEN } = require('iceworks-events'); - export default (app) => { - app.io.of('/').route(ICEWORKS_TASK_DEV_OPEN, app.io.controller.tasks.dev); + const { controller } = app.io; + const { project } = controller; + + app.io.route('project.index.devStart', project.index.devStart); + app.io.route('project.index.devStop', project.index.devStop); + app.io.route('project.index.list', project.index.list); + app.io.route('project.index.current', project.index.getCurrent); + app.io.route('project.index.setCurrent', project.index.setCurrent); + app.io.route('project.page.list', project.page.list); + app.io.route('project.dependency.list', project.dependency.list); }; diff --git a/packages/iceworks-server/src/app/view/index.html b/packages/iceworks-server/src/app/view/index.html index 6f2330dfce..457fe0d60f 100644 --- a/packages/iceworks-server/src/app/view/index.html +++ b/packages/iceworks-server/src/app/view/index.html @@ -24,6 +24,7 @@ diff --git a/packages/iceworks-server/src/config/config.default.ts b/packages/iceworks-server/src/config/config.default.ts index a63723e5e3..9133f190b0 100644 --- a/packages/iceworks-server/src/config/config.default.ts +++ b/packages/iceworks-server/src/config/config.default.ts @@ -17,6 +17,11 @@ export = (appInfo: any) => { }, }; + config.cors = { + origin: '*', + allowMethods: 'GET,PUT,POST,DELETE' + }; + config.view = { defaultViewEngine: 'nunjucks', mapping: { @@ -24,5 +29,12 @@ export = (appInfo: any) => { }, }; + config.security = { + csrf: { + headerName: 'x-csrf-token', + ignore: ctx => ctx.ip === '127.0.0.1', + }, + }; + return config; }; diff --git a/packages/iceworks-server/src/config/plugin.ts b/packages/iceworks-server/src/config/plugin.ts index e7c3ed0ef3..3a1c843b00 100644 --- a/packages/iceworks-server/src/config/plugin.ts +++ b/packages/iceworks-server/src/config/plugin.ts @@ -1,4 +1,5 @@ -// had enabled by midway +import * as path from 'path'; + export = { nunjucks: { enable: true, @@ -9,4 +10,14 @@ export = { enable: true, package: 'egg-socket.io', }, + + cors: { + enable: true, + package: 'egg-cors', + }, + + projectManager: { + enable: true, + path: path.join(__dirname, '../lib/plugin/project-manager'), + } }; diff --git a/packages/iceworks-server/src/interface.ts b/packages/iceworks-server/src/interface.ts deleted file mode 100644 index b5d54ddaf7..0000000000 --- a/packages/iceworks-server/src/interface.ts +++ /dev/null @@ -1,23 +0,0 @@ -/** - * @description User-Service parameters - */ -export interface IUserOptions { - id: number; -} - -/** - * @description User-Service response - */ -export interface IUserResult { - id: number; - username: string; - phone: string; - email?: string; -} - -/** - * @description User-Service abstractions - */ -export interface IUserService { - getUser(options: IUserOptions): Promise; -} diff --git a/packages/iceworks-server/src/interface/index.ts b/packages/iceworks-server/src/interface/index.ts new file mode 100644 index 0000000000..29d6005c78 --- /dev/null +++ b/packages/iceworks-server/src/interface/index.ts @@ -0,0 +1,10 @@ +export * from './project'; +export * from './material'; + +export interface IPluginGetAllResult { + data: any[]; +} + +export interface IPluginService { + getAll(projectFolderPath: string): Promise; +} diff --git a/packages/iceworks-server/src/interface/material.ts b/packages/iceworks-server/src/interface/material.ts new file mode 100644 index 0000000000..1ad93d67f2 --- /dev/null +++ b/packages/iceworks-server/src/interface/material.ts @@ -0,0 +1,19 @@ +/** + * TODO 物料的模板信息 + */ +export interface IMaterialScaffold { + +} + +/** + * TODO 物料的区块信息 + */ +export interface IMaterialBlock { + +} +/** + * TODO 物料的组件信息 + */ +export interface IMaterialComponent { + +} diff --git a/packages/iceworks-server/src/interface/project.ts b/packages/iceworks-server/src/interface/project.ts new file mode 100644 index 0000000000..96a89fe34d --- /dev/null +++ b/packages/iceworks-server/src/interface/project.ts @@ -0,0 +1,533 @@ +import { IMaterialBlock, IMaterialComponent } from './material'; +import * as EventEmitter from 'events'; + +/** + * 项目的路由 + */ +export interface IProjectRouter { + /** + * URL 路径 + */ + path: string; + + /** + * 页面名 + */ + pageName: string; +} + +/** + * 项目的 mock + */ +export interface IProjectMock { + /** + * 路径 + */ + path: string; + + /** + * 方法 + */ + method: string; + + /** + * 状态码 + */ + status: number; + + /** + * 返回主体 + */ + body: string; +} + +/** + * 项目的菜单 + */ +export interface IProjectMenu { + /** + * 位置 + */ + position: 'header' | 'aside'; + + /** + * 名称 + */ + name: string; + + /** + * URL 路径 + */ + path: string; + + /** + * 图标标识 + */ + icon?: string; + + /** + * 是否新窗口打开 + */ + newWindow?: boolean; +} + +/** + * 项目的 Todo + */ +export interface IProjectTodo { + /** + * 文件路径 + */ + filePath: string; + + /** + * 文件内的 todo + */ + messages: Array<{ + + /** + * 在第几行 + */ + line: string; + + /** + * 文本 + */ + text: string; + }>; +} + +/** + * 项目的依赖信息 + */ +export interface IProjectDependency { + /** + * 包名 + */ + package: string; + + /** + * 指定版本:^1.0.1 / ~1.0.1 / 0.0.x + */ + specifyVersion: string; + + /** + * 当前本地版本:1.0.3 + */ + localVersion?: string; + + /** + * 是否可更新:当远程有 1.0.4 时,该值为 true + */ + canUpdate?: boolean; + + /** + * 是否本地依赖 devDependencies ? + */ + dev: boolean; +} + +/** + * 项目的区块 + */ +export interface IProjectBlock { + /** + * 名称 + */ + name: string; + + /** + * 本地文件夹路径 + */ + folderPath?: string; + + /** + * 背景图 + */ + image?: string; +} + +/** + * 项目的组件 + */ +export interface IProjectComponent { + /** + * 名称 + */ + name: string; + + /** + * 是否可更新 + */ + canUpdate?: boolean; +} + +/** + * 项目的模板 + */ +export interface IProjectScaffold { + /** + * 名称 + */ + name: string; + + /** + * 标题 + */ + title: string; + + /** + * 背景图 + */ + image?: string; +} + +/** + * TODO 项目的布局 + */ +export interface IProjectLayout { + +} + +/** + * 项目的页面 + */ +export interface IProjectPage { + /** + * 名称 + */ + name: string; + + /** + * 文件路径 + */ + folderPath: string; + + /** + * 此文件的创建时间的时间戳 + */ + birthtime: string; + + /** + * 上次访问此文件的时间戳 + */ + atime?: string; + + /** + * 上次更改文件状态的时间戳 + */ + ctime?: string; + + /** + * 上次修改此文件的时间戳 + */ + mtime?: string; + + /** + * 页面内的区块 + */ + blocks?: IProjectBlock[]; +} + +/** + * 创建页面的参数 + */ +export interface ICreatePageParam { + /** + * 名称 + */ + name: string; + + /** + * 使用的布局 + */ + layout: IProjectLayout; + + /** + * 页面内的区块 + */ + blocks?: IProjectBlock[]; + + /** + * 路由路径 + */ + routePath: string; + + /** + * 菜单名 + */ + menuName?: string; +} + +/** + * 项目 + * + * - 'dev.data' 事件 + * - 'dev.error' 事件 + * - 'dev.exit' 事件 + */ +export interface IProject extends EventEmitter { + /** + * 项目名称 + */ + name: string; + + /** + * 项目文件夹路径 + */ + folderPath: string; + + /** + * 启动调试服务 + * + * @param settingsEnv 环境变量 + */ + devStart(settingsEnv: object): Promise; + + /** + * 停止调试服务 + */ + devStop(): Promise; + + /** + * 执行构建 + * + * @param settingsEnv 环境变量 + */ + build(settingsEnv: object): Promise; + + /** + * 获取项目内的布局 + */ + getLayouts(): Promise; + + /** + * 获取单个布局的信息 + * + * @param layoutName 布局名 + */ + getLayout(layoutName: string): Promise; + + /** + * 获取项目内的页面信息 + */ + getPages(): Promise; + + /** + * 获取单个页面的信息 + * + * @param pageName 页面名 + */ + getPage(pageName): Promise; + + /** + * 添加多个页面到项目 + * + * @param pages 页面配置信息 + */ + createPages(pages: ICreatePageParam[]): Promise; + + /** + * 添加单个页面到项目 + * + * - 根据布局和区块生成页面文件 + * - 添加菜单 + * - 添加路由 + * + * @param page 页面配置 + */ + createPage(page: ICreatePageParam): Promise; + + /** + * 删除项目内的页面 + * + * @param pageName 页面名 + */ + deletePage(pageName: string): Promise; + + /** + * 更新页面 + * + * @param page 页面信息 + */ + updatePage(page: IProjectPage): Promise; + + /** + * 获取区块列表 + * + * @param pageName 页面名称,如果无则获取项目的区块 + */ + getBlocks(pageName?: string): Promise; + + /** + * 添加区块列表 + * + * @param blocks 区块列表 + * @param pageName 页面名称,如果无则添加区块列表到项目 + */ + createBlocks(blocks: IMaterialBlock[], pageName?: string): Promise; + + /** + * 添加区块 + * + * @param block 区块信息 + * @param pageName 页面名称,如果无则添加区块的项目 + */ + createBlock(block: IMaterialBlock, pageName?: string): Promise; + + /** + * 获取项目内的组件 + */ + getComponents(): Promise; + + /** + * 添加多个组件到项目 + * + * @param components 组件信息 + */ + createComponents(components: IMaterialComponent[]): Promise; + + /** + * 添加组件到项目 + * + * @param component 组件信息 + */ + createComponent(component: IMaterialComponent): Promise; + + /** + * 升级某个组件 + * + * @param name 组件名 + */ + upgradeComponent(name: string): Promise; + + /** + * 获取项目内的依赖 + */ + getDependencies(): Promise; + + /** + * 添加多个依赖到项目 + * + * @param dependencies 依赖列表 + */ + createDependencies(dependencies: IProjectDependency[]): Promise; + + /** + * 添加依赖到项目 + * + * @param dependency 依赖信息 + */ + createDependency(dependency: IProjectDependency): Promise; + + /** + * 升级项目中的某个依赖 + * + * @param denpendency 指定依赖 + */ + upgradeDependency(denpendency: {name: string, isDev: boolean}): Promise; + + /** + * 获取项目内的 todo + */ + getTodos(): Promise; + + /** + * 获取项目菜单 + */ + getMenus(): Promise; + + /** + * 添加多个菜单到项目 + * + * @param menus 多个菜单配置 + */ + createMenus(menus: IProjectMenu[]): Promise; + + /** + * 添加菜单 + * + * @param menu 菜单配置 + */ + createMenu(menu: IProjectMenu): Promise; + + /** + * 删除菜单 + * + * @param menu 菜单配置 + */ + deleteMenu(menu: IProjectMenu): Promise; + + /** + * 更新菜单 + * + * @param menu 菜单配置 + */ + updateMenu(menu: IProjectMenu): Promise; + + /** + * 获取项目路由 + */ + getRouters(): Promise; + + /** + * 添加多个路由到项目 + * + * @param routers 多个路由配置 + */ + createRouters(routers: IProjectRouter[]): Promise; + + /** + * 添加路由 + * + * @param router 路由配置 + */ + createRouter(router: IProjectRouter): Promise; + + /** + * 删除路由 + * + * @param path 路由路径 + */ + deleteRouter(path: string): Promise; + + /** + * 更新路由 + * + * @param router 路由配置 + */ + updateRouter(router: IProjectRouter): Promise; + + /** + * 获取项目的数据模拟配置 + */ + getMocks(): Promise; + + /** + * 添加多个数据模拟到项目 + * + * @param mocks 数据模拟配置 + */ + createMocks(mocks: IProjectMock[]): Promise; + + /** + * 添加数据模拟 + * + * @param mock 数据模拟配置 + */ + createMock(mock: IProjectMock): Promise; + + /** + * 删除数据模拟 + * + * @param mock 数据模拟配置 + */ + deleteMock(mock: IProjectMock): Promise; + + /** + * 更新数据模拟 + * + * @param mock 数据模拟配置 + */ + updateMock(mock: IProjectMock): Promise; +} diff --git a/packages/iceworks-server/src/lib/adapter/project.ts b/packages/iceworks-server/src/lib/adapter/project.ts new file mode 100644 index 0000000000..2cef36a021 --- /dev/null +++ b/packages/iceworks-server/src/lib/adapter/project.ts @@ -0,0 +1,124 @@ +import * as path from 'path'; +import * as pathExists from 'path-exists'; +import * as fs from 'fs'; +import * as util from 'util'; +import * as child_process from 'child_process'; +import * as EventEmitter from 'events'; +import * as detectPort from 'detect-port'; +import junk from 'junk'; +import { IProjectPage, IProjectDependency } from '../../interface'; + +const readdirAsync = util.promisify(fs.readdir); + +const readdir = async (targetPath) => { + if (pathExists.sync(targetPath)) { + return (await readdirAsync(targetPath)).filter(junk.not); + } + return []; +}; + +const recursive = async function(dirPath) { + const list = []; + const files = await readdir(dirPath); + files.forEach(function(file) { + const fullPath = path.join(dirPath, file); + const stats = fs.lstatSync(fullPath); + if (stats.isDirectory()) { + const { atime, birthtime, ctime, mtime } = stats; + list.push({ + name: path.basename(fullPath), + fullPath, + atime, + birthtime, + ctime, + mtime, + }); + } + }); + + return list; +}; + +const DEFAULT_PORT = '4444'; + +export const DEV_STATUS_NORMAL = 'normal'; +export const DEV_STATUS_STARING = 'staring'; +export const DEV_STATUS_WORKING = 'working'; +export const DEV_STATUS_STOP = 'stop'; + +export default class Project extends EventEmitter { + public readonly name: string; + + public readonly folderPath: string; + + private devProcess: child_process.ChildProcess; + + public devStatus: string = DEV_STATUS_NORMAL; + + constructor(folderPath: string) { + super(); + this.name = path.basename(folderPath); + this.folderPath = folderPath; + } + + async getPages(): Promise { + return recursive(path.join(this.folderPath, 'src', 'pages')); + } + + async getDependencies(): Promise { + return [ + { + package: 'icestore', + dev: false, + specifyVersion: '^0.1.0' + } + ]; + } + + async devStart(settingsEnv: object): Promise { + const port = await detectPort(DEFAULT_PORT); + const { folderPath } = this; + const env = { PORT: port }; + + if (this.devProcess) { + throw new Error('调试服务已启动,不能多次启动,请先停止已启动的调试服务后再次启动'); + } + + const childProcess = child_process.spawn('npm', ['start'], { + cwd: folderPath, + env: Object.assign({}, settingsEnv, env) + }); + + this.devStatus = DEV_STATUS_WORKING; + this.devProcess = childProcess; + + childProcess.stdout.on('data', (data) => { + this.emit('dev.data', data); + }); + + childProcess.on('error', (data) => { + this.devStatus = DEV_STATUS_STOP; + this.devProcess = null; + this.emit('dev.error', data); + }); + + childProcess.on('exit', (code, signal) => { + this.devStatus = DEV_STATUS_STOP; + this.emit('dev.exit', code, signal); + }); + + return this; + } + + async devStop(): Promise { + if (!this.devProcess) { + throw new Error('没有启动调试服务,无法停止。'); + } + + this.devProcess.kill(); + this.devProcess = null; + this.devStatus = DEV_STATUS_STOP; + + return this; + } +} diff --git a/packages/iceworks-server/src/lib/getEnv.ts b/packages/iceworks-server/src/lib/getEnv.ts new file mode 100644 index 0000000000..07ce2689ef --- /dev/null +++ b/packages/iceworks-server/src/lib/getEnv.ts @@ -0,0 +1,41 @@ +import * as npmRunPath from 'npm-run-path'; +import * as path from 'path'; +import * as os from 'os'; + +const isWin = os.type() === 'Windows_NT'; + +// const settings = require('./services/settings'); +// settings.get('registry') +const registry = 'https://registry.npm.taobao.org'; + +export default function() { + // https://github.com/sindresorhus/npm-run-path + // Returns the augmented process.env object. + const npmEnv = npmRunPath.env(); + + // Merge process.env、npmEnv and custom environment variables + const env = Object.assign({}, process.env, npmEnv, { + // eslint-disable-next-line + npm_config_registry: registry, + // eslint-disable-next-line + yarn_registry: registry, + CLICOLOR: 1, + FORCE_COLOR: 1, + COLORTERM: 'truecolor', + TERM: 'xterm-256color', + ICEWORKS_IPC: 'yes', + }); + + const pathEnv = [process.env.PATH, npmEnv.PATH].filter( + (p) => !!p + ); + + if (isWin) { + // do something + } else { + pathEnv.push('/usr/local/bin'); + env.PATH = pathEnv.join(path.delimiter); + } + + return env; +} diff --git a/packages/iceworks-server/src/lib/plugin/project-manager/app.ts b/packages/iceworks-server/src/lib/plugin/project-manager/app.ts new file mode 100644 index 0000000000..5ae6981f00 --- /dev/null +++ b/packages/iceworks-server/src/lib/plugin/project-manager/app.ts @@ -0,0 +1,60 @@ +import * as EventEmitter from 'events'; +import storage from '../../storage'; +import Project from '../../adapter/project'; +import getEnv from '../../getEnv'; + +class ProjectManager { + private projects: Project[]; + + async ready() { + const projectFolderPaths = storage.get('projects'); + this.projects = await Promise.all(projectFolderPaths.map(async (projectFolderPath) => { + const project = new Project(projectFolderPath); + return project; + })); + } + + getProjects(): Project[] { + return this.projects; + } + + getProject(projectFolderPath: string): Project { + const project = this.projects.find(({ folderPath }) => folderPath === projectFolderPath); + if (!project) { + throw new Error('没有找到对应的项目'); + } + + return project; + } + + getCurrent(): Project { + const projectFolderPath = storage.get('project'); + return this.getProject(projectFolderPath); + } + + setCurrent(projectFolderPath: string): Project { + storage.set('project', projectFolderPath); + return this.getProject(projectFolderPath); + } + + async devStart(projectFolderPath: string): Promise { + const project = this.getProject(projectFolderPath); + return project.devStart(getEnv()); + } + + async devStop(projectFolderPath: string) { + const project = this.getProject(projectFolderPath); + return project.devStop(); + } + + async build() {} + + async lint() {} +} + +export default app => { + app.projectManager = new ProjectManager(); + app.beforeStart(async () => { + await app.projectManager.ready(); + }); +}; diff --git a/packages/iceworks-server/src/lib/plugin/project-manager/package.json b/packages/iceworks-server/src/lib/plugin/project-manager/package.json new file mode 100644 index 0000000000..2b4e18ee9c --- /dev/null +++ b/packages/iceworks-server/src/lib/plugin/project-manager/package.json @@ -0,0 +1,5 @@ +{ + "eggPlugin": { + "name": "projectManager" + } +} \ No newline at end of file diff --git a/packages/iceworks-server/src/lib/service/dependency.ts b/packages/iceworks-server/src/lib/service/dependency.ts new file mode 100644 index 0000000000..3427828eea --- /dev/null +++ b/packages/iceworks-server/src/lib/service/dependency.ts @@ -0,0 +1,27 @@ +import { provide, plugin } from 'midway'; +import { IPluginService, IPluginGetAllResult } from '../../interface'; + +@provide('dependencyService') +export class DependencyService implements IPluginService { + @plugin('projectManager') + private projectManager; + + async getAll(projectFolderPath: string): Promise { + const project = this.projectManager.getProject(projectFolderPath); + return { + data: project ? await project.getDependencies() : [] + }; + } + + async getOne() { + + } + + async create() { + + } + + async delete() { + + } +} diff --git a/packages/iceworks-server/src/lib/service/page.ts b/packages/iceworks-server/src/lib/service/page.ts new file mode 100644 index 0000000000..89316ad76d --- /dev/null +++ b/packages/iceworks-server/src/lib/service/page.ts @@ -0,0 +1,28 @@ +import { provide, plugin } from 'midway'; +import { IPluginService, IPluginGetAllResult } from '../../interface'; + +@provide('pageService') +export class PageService implements IPluginService { + @plugin('projectManager') + private projectManager; + + async getAll(projectFolderPath: string): Promise { + const project = this.projectManager.getProject(projectFolderPath); + + return { + data: project ? await project.getPages() : [] + }; + } + + async getOne() { + + } + + async create() { + + } + + async delete() { + + } +} diff --git a/packages/iceworks-server/src/lib/storage.ts b/packages/iceworks-server/src/lib/storage.ts new file mode 100644 index 0000000000..1dbf6faee1 --- /dev/null +++ b/packages/iceworks-server/src/lib/storage.ts @@ -0,0 +1,80 @@ +import * as path from 'path'; +import * as Conf from 'conf'; +import * as mkdirp from 'mkdirp'; + + // @TODO +const defaultCwd = path.join(__dirname, '../../data'); +mkdirp.sync(defaultCwd); + +class DataStore extends Conf { + constructor(options?) { + options = { + name: 'config', + ...options + }; + + if (options.cwd) { + options.cwd = path.isAbsolute(options.cwd) ? options.cwd : path.join(defaultCwd, options.cwd); + } else { + options.cwd = defaultCwd; + } + + options.configName = options.name; + delete options.name; + super(options); + } +} + +class Store { + private store: Conf; + + constructor(options?) { + this.store = new DataStore(options); + } + + set(key: string, values: any): void { + this.store.set(key, values); + } + + get(key: string): any { + return this.store.get(key); + } + + add(key: string, value: string): void { + const values = this.store.get(key); + if (Array.isArray(values)) { + this.store.set(key, values.filter((v) => v !== value).unshift(value)); + } + } + + remove(key: string, value: string): void { + const values = this.store.get(key) || []; + if (Array.isArray(values)) { + this.store.set(key, values.filter((v) => v !== value)); + } + } + + has(key: string, value: string): boolean { + const values = this.store.get(key); + return Array.isArray(values) ? values.some((v) => v === value) : false; + } + + delete(key: string): void { + this.store.delete(key); + } +} + +const schema = { + 'project': { + type: 'string', + }, + 'projects': { + type: 'array', + items: { + type: 'string', + }, + default: [] + } +}; + +export default new Store({schema}); diff --git a/packages/iceworks-server/src/service/user.ts b/packages/iceworks-server/src/service/user.ts deleted file mode 100644 index 8b53f77b60..0000000000 --- a/packages/iceworks-server/src/service/user.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { provide } from 'midway'; -import { IUserService, IUserOptions, IUserResult } from '../interface'; - -@provide('userService') -export class UserService implements IUserService { - - async getUser(options: IUserOptions): Promise { - return { - id: options.id, - username: 'mockedName', - phone: '12345678901', - email: 'xxx.xxx@xxx.com', - }; - } -}