diff --git a/Makefile b/Makefile index 41fadbb..b4ed70e 100644 --- a/Makefile +++ b/Makefile @@ -1,66 +1,82 @@ -SOURCES=src/node_modules $(shell find src -type f) -NWDIR=./node_modules/node-webkit-builder -NWBUILD=$(NWDIR)/bin/nwbuild.linux -VERSION=$(shell cat src/package.json | grep -F '"version":' | grep -o "[0-9]\+.[0-9]\+.[0.9]\+") - -.PHONY: build clean build-linux32 build-linux64 build-windows build-osx dist release - -build: build-linux32 build-linux64 build-windows build-osx - -build-linux32: build/json-server-gui/linux32/json-server-gui - -build-linux64: build/json-server-gui/linux64/json-server-gui - -build-windows: build/json-server-gui/win/json-server-gui.exe - -build-osx: build/json-server-gui/osx/json-server-gui.app - -dist: clean build - @rm -rf dist/$(VERSION) - cd build/json-server-gui && mv linux32 json-server-gui-linux32 && tar zcvf json-server-gui-linux32.tar.gz json-server-gui-linux32 && rm -rf json-server-gui-linux32 - cd build/json-server-gui && mv linux64 json-server-gui-linux64 && tar zcvf json-server-gui-linux64.tar.gz json-server-gui-linux64 && rm -rf json-server-gui-linux64 - cd build/json-server-gui && mv osx json-server-gui-osx && zip -r json-server-gui-osx.zip json-server-gui-osx && rm -rf json-server-gui-osx - cd build/json-server-gui && mv win json-server-gui-win && zip -r json-server-gui-win.zip json-server-gui-win && rm -rf json-server-gui-win - mkdir -p dist/$(VERSION) - mv build/json-server-gui/json-server-gui-linux32.tar.gz dist/$(VERSION)/ - mv build/json-server-gui/json-server-gui-linux64.tar.gz dist/$(VERSION)/ - mv build/json-server-gui/json-server-gui-osx.zip dist/$(VERSION)/ - mv build/json-server-gui/json-server-gui-win.zip dist/$(VERSION)/ - -release: dist - mv dist/$(VERSION) ~/Dropbox/Public/json-server-gui/ - sed -i "s/json-server-gui\/[0-9]\+.[0-9]\+.[0-9]\+\/json-server-gui-/json-server-gui\/$(VERSION)\/json-server-gui-/g" README.md - -clean: - rm -rf build - -$(NWBUILD): node_modules - cp $(NWDIR)/bin/nwbuild $(NWDIR)/bin/nwbuild.win - tr -d '\015' < $(NWDIR)/bin/nwbuild.win > $@ - chmod +x $@ - -src/node_modules: - cd src && npm install - -node_modules: - npm install - -build/json-server-gui/linux32/json-server-gui: $(NWBUILD) $(SOURCES) - @mv src/db.json db.json.bak 2> /dev/null || echo "no db.json" - $(NWBUILD) -p linux32 -o build src - @mv db.json.bak src/db.json 2> /dev/null || echo "no db.json" - -build/json-server-gui/linux64/json-server-gui: $(NWBUILD) $(SOURCES) - @mv src/db.json db.json.bak 2> /dev/null || echo "no db.json" - $(NWBUILD) -p linux64 -o build src - @mv db.json.bak src/db.json 2> /dev/null || echo "no db.json" - -build/json-server-gui/win/json-server-gui.exe: $(NWBUILD) $(SOURCES) - @mv src/db.json db.json.bak 2> /dev/null || echo "no db.json" - $(NWBUILD) -p win -o build src - @mv db.json.bak src/db.json 2> /dev/null || echo "no db.json" - -build/json-server-gui/osx/json-server-gui.app: $(NWBUILD) $(SOURCES) - @mv src/db.json db.json.bak 2> /dev/null || echo "no db.json" - $(NWBUILD) -p osx -o build src - @mv db.json.bak src/db.json 2> /dev/null || echo "no db.json" +VERSION = $(shell cat src/package.json | grep -F version | grep -o "[0-9]\+.[0-9]\+.[0.9]\+") + +ifndef NPM + +NPM = npm + +endif + +build: build-linux32 build-linux64 build-windows32 build-windows64 + +build-linux32: build/linux32 + +build-linux64: build/linux64 + +build-windows32: build/win32 + +build-windows64: build/win64 + +build-osx: build/osx + +dist: clean build + @rm -rf dist/$(VERSION) + cd build/json-server-gui && mv linux32 json-server-gui-linux32 && tar zcvf json-server-gui-linux32.tar.gz json-server-gui-linux32 && rm -rf json-server-gui-linux32 + cd build/json-server-gui && mv linux64 json-server-gui-linux64 && tar zcvf json-server-gui-linux64.tar.gz json-server-gui-linux64 && rm -rf json-server-gui-linux64 + cd build/json-server-gui && mv osx json-server-gui-osx && zip -r json-server-gui-osx.zip json-server-gui-osx && rm -rf json-server-gui-osx + cd build/json-server-gui && mv win32 json-server-gui-win32 && zip -r json-server-gui-win32.zip json-server-gui-win32 && rm -rf json-server-gui-win32 + cd build/json-server-gui && mv win64 json-server-gui-win64 && zip -r json-server-gui-win64.zip json-server-gui-win64 && rm -rf json-server-gui-win64 + mkdir -p dist/$(VERSION) + mv build/json-server-gui/json-server-gui-linux32.tar.gz dist/$(VERSION)/ + mv build/json-server-gui/json-server-gui-linux64.tar.gz dist/$(VERSION)/ + mv build/json-server-gui/json-server-gui-osx.zip dist/$(VERSION)/ + mv build/json-server-gui/json-server-gui-win32.zip dist/$(VERSION)/ + mv build/json-server-gui/json-server-gui-win64.zip dist/$(VERSION)/ + +release: dist + mv dist/$(VERSION) ~/Dropbox/Public/json-server-gui/ + sed -i "s/json-server-gui\/[0-9]\+.[0-9]\+.[0-9]\+\/json-server-gui-/json-server-gui\/$(VERSION)\/json-server-gui-/g" README.md + +clean: + rm -rf build + +src/node_modules: + cd src/ && npm install + +node_modules: src/node_modules + npm install + +update: + cd src/ && npm update + npm update + +build/linux32: node_modules + @mv src/db.json db.json.bak 2> /dev/null || echo no db.json + $(NPM) run build-linux32 + @mv db.json.bak src/db.json 2> /dev/null || echo + @touch build/linux32 + +build/linux64: node_modules + @mv src/db.json db.json.bak 2> /dev/null || echo no db.json + $(NPM) run build-linux64 + @mv db.json.bak src/db.json 2> /dev/null || echo + @touch build/linux64 + +build/win32: node_modules + @mv src/db.json db.json.bak 2> /dev/null || echo no db.json + $(NPM) run build-win32 + @mv db.json.bak src/db.json 2> /dev/null || echo + @touch build/win32 + +build/win64: node_modules + @mv src/db.json db.json.bak 2> /dev/null || echo no db.json + $(NPM) run build-win64 + @mv db.json.bak src/db.json 2> /dev/null || echo + @touch build/win64 + +build/osx: node_modules + @mv src/db.json db.json.bak 2> /dev/null || echo no db.json + $(NPM) run build-osx + @mv db.json.bak src/db.json 2> /dev/null || echo + @touch build/osx + +.PHONY: build clean build-linux32 build-linux64 build-windows build-osx dist release diff --git a/README.md b/README.md index 1b18f97..f9e406e 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ How? ### Download -Pre-built binaries for latest version are available here: +Pre-built binaries for latest version are available here (not available): * [Linux - 32 bits](https://dl.dropboxusercontent.com/u/6414656/json-server-gui/2.0.0/json-server-gui-linux32.tar.gz) (~40.3M) * [Linux - 64 bits](https://dl.dropboxusercontent.com/u/6414656/json-server-gui/2.0.0/json-server-gui-linux64.tar.gz) (~38.6M) @@ -31,7 +31,7 @@ Pre-built binaries for latest version are available here: ### Build -Clone the repository, then run `make`. The project will build for Linux (32 & 64 bits), Windows (32 bits), and Max OSX. +Clone the repository, then run `make`. The project will build for Linux (32 & 64 bits), Windows (32 & 64 bits), and Max OSX. It can last about a century first time as it will download all corresponding `node-webkit` distributions. @@ -40,7 +40,8 @@ To build specific for a specific platform: ```sh make build-linux32 make build-linux64 -make build-windows +make build-windows32 +make build-windows64 make build-osx ``` @@ -48,8 +49,11 @@ Moar! ----- * `$APP_DIR/public` is served as document root +* `$APP_DIR/config/config.json` is served as configuration file (JSON format) + * `DataPath` = directory where we'll search for `db.json` and `public` folder (default = app's folder) + * `Port` = server's port (default = 26080) * `$APP_DIR/db.json` is your data file -* Some behavior can be defined from environment variables: +* Some behavior can be defined from environment variables (if not set in the `config.json` file): * `APP_DIR` = directory where we'll search for `db.json` and `public` folder (default = app's folder) * `PORT` = server's port (default = 26080) @@ -58,11 +62,20 @@ TODO * Better GUI * Persisted configuration (instead of env) +* Use less tricks to pass events How to contribute ----------------- * Fork & clone -* Install [node-webkit](https://github.com/rogerwang/node-webkit#downloads) for your platform (alternatively, you can run `make build-` and grab node-webkit from `node_modules/node-webkit-builder/cache/0.10.5//`, saving you a duplicate download) +* Install [node-webkit](https://github.com/rogerwang/node-webkit#downloads) for your platform (alternatively, you can run `make build-` and grab node-webkit from `node_modules/nw-builder/cache/0.10.5//`, saving you a duplicate download) * Make your changes and test them by running `/path/to/nw src` * Create a pull request + +Contributions +------------- + +* Persistent configuration file +* Auto-reload when file changes +* Button to start and stop json-server without exiting GUI +* Update to last version of `json-server` and `node-webkit` \ No newline at end of file diff --git a/package.json b/package.json index 2c22277..c4c7536 100644 --- a/package.json +++ b/package.json @@ -3,14 +3,16 @@ "version": "1.0.1", "description": "JSON Server GUI - builder", "devDependencies": { - "node-webkit-builder": "^0.1.3" + "nw-builder": "latest" }, "scripts": { - "fix-nwbuild": "cp ./node_modules/.bin/nwbuild ./node_modules/.bin/nwbuild.win && tr -d '\\015' < ./node_modules/.bin/nwbuild.win > ./node_modules/.bin/nwbuild", - "build-win": "nwbuild -p win src", - "build-linux32": "nwbuild -p linux32 src", + "build-win64": "nwbuild -p win64 src", + "build-win32": "nwbuild -p win32 src", + "build-win": "nwbuild -p win32,win64 src", "build-linux64": "nwbuild -p linux64 src", + "build-linux32": "nwbuild -p linux32 src", + "build-linux": "nwbuild -p linux32,linux64 src", "build-osx": "nwbuild -p osx src", - "build-all": "nwbuild -p linux64,linux32,win,osx src" + "build-all": "nwbuild -p osx,win64,win32,linux64,linux32 src" } } diff --git a/src/client.js b/src/client.js index bd9ddc3..e89e03f 100644 --- a/src/client.js +++ b/src/client.js @@ -1,44 +1,73 @@ -// Escape = close app -document.addEventListener("keydown", function (e) { - if (e.keyCode == 27) { - process.exit(0); - } -}); - -// Thanks http://stackoverflow.com/questions/4810841/how-can-i-pretty-print-json-using-javascript -function syntaxHighlight(json) { - json = json.replace(/&/g, '&').replace(//g, '>'); - return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) { - var cls = 'number'; - if (/^"/.test(match)) { - if (/:$/.test(match)) { - cls = 'key'; - } else { - cls = 'string'; - } - } else if (/true|false/.test(match)) { - cls = 'boolean'; - } else if (/null/.test(match)) { - cls = 'null'; - } - return '' + match + ''; - }); -} - -// Refresh listing -var elData = document.getElementById("data"); -elData.innerHTML = syntaxHighlight(JSON.stringify(app.low.db, null, 2)); -process.on("data-update", function () { - elData.innerHTML = syntaxHighlight(JSON.stringify(app.low.db, null, 2)); -}); - -// Logs -var elLogs = document.getElementById("logs"); -process.on("request", function (method, url, body) { - var li = "
  • " + method + " " + url + ""; - if (method !== "GET") { - li += "
    " + JSON.stringify(body) + ""; - } - li += "
  • "; - elLogs.innerHTML += li; -}); +// Escape = close app +document.addEventListener("keydown", function (e) { + if (e.keyCode == 27) { + process.exit(0); + } +}); + +// Thanks http://stackoverflow.com/questions/4810841/how-can-i-pretty-print-json-using-javascript +function syntaxHighlight(json) { + if (typeof json === "undefined") { + return ""; + } + json = json.replace(/&/g, '&').replace(//g, '>'); + return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) { + var cls = 'number'; + if (/^"/.test(match)) { + if (/:$/.test(match)) { + cls = 'key'; + } else { + cls = 'string'; + } + } else if (/true|false/.test(match)) { + cls = 'boolean'; + } else if (/null/.test(match)) { + cls = 'null'; + } + return '' + match + ''; + }); +} + +var serv = true; + +function clearcontent() +{ + elLogs.innerHTML = "
  • Serveur: http://localhost:" + port + "/ | Status:
  • \ +
  • Clear logs | " + (serv ? "Stop server" : "Start server") + "
  • "; + process.emit("data-update"); + conn(null); +} + +function btnSwitchServ() +{ + serv = !serv; + document.getElementById("btnServ").innerHTML = (serv ? "Stop server" : "Start server"); + if (!serv) + { + stop_server(); + } + else + { + start_server(); + } +} + +// Refresh listing +var elData = document.getElementById("data"); +console.log(server); +elData.innerHTML = syntaxHighlight(JSON.stringify(router.db.getState(), null, 2)); +process.on("data-update", function () { + elData.innerHTML = syntaxHighlight(JSON.stringify(router.db.getState(), null, 2)); +}); + +// Logs +var elLogs = document.getElementById("logs"); +process.on("request", function (method, url, body) { + var li = '
  • ' + method + " " + url + ''; + if (method !== "GET" && method !== "DELETE") { + li += '
    ' + JSON.stringify(body) + ''; + } + li += '
  • '; + elLogs.innerHTML += li; + process.emit("data-update"); +}); \ No newline at end of file diff --git a/src/config/config.json b/src/config/config.json new file mode 100644 index 0000000..fb6d9ec --- /dev/null +++ b/src/config/config.json @@ -0,0 +1,5 @@ +{ + "Comment": "This is the default configuration :", + "Port": 26080, + "DataPath": "." +} \ No newline at end of file diff --git a/src/index.html b/src/index.html index a5f5f5e..11a75ff 100644 --- a/src/index.html +++ b/src/index.html @@ -3,15 +3,31 @@ JSON Server +
    
           
      -
    • Serveur: http://localhost:/
    • +
    • Serveur: http://localhost:/ | Status:
    • +
    • Clear logs | Stop server
    + diff --git a/src/package.json b/src/package.json index e78a330..dd8cf17 100644 --- a/src/package.json +++ b/src/package.json @@ -1,28 +1,26 @@ { "name": "json-server-gui", - "version": "2.0.0", + "version": "3.0.2", "description": "JSON Server", "main": "index.html", "nodejs": true, - "single-instance": true, + "dependencies": { + "json-server": "latest" + }, "window": { + "id": "json_server_gui_view", "title": "JSON Server", "fullscreen": false, "resizable": true, - "always-on-top": false, + "always_on_top": false, "frame": true, "height": 600, "min_width": 800, - "show_in_taskbar": true, "width": 800, - "toolbar": false - }, - "dependencies": { - "json-server": "0.4.2" + "show_in_taskbar": true }, "webkit": { "page-cache": false, - "java": false, "plugin": false } } diff --git a/src/server.js b/src/server.js index ae3d7a1..39374b3 100644 --- a/src/server.js +++ b/src/server.js @@ -1,77 +1,120 @@ -var http = require("http"); -var path = require("path"); -var fs = require("fs"); - - -// Monkey-patch json-server routes to trigger event -var routes = require("json-server/src/routes"); -for (var route in routes) { - routes[route] = wrapRoute(route, routes[route]); -} -function wrapRoute (name, route) { - return function (req, res, next) { - ping(name, req); - route(req, res, next); - } -} - - -// Get current directory -var appDir = process.env.APP_DIR || process.cwd(); -// Get execPath -// /path/to/nw if run as "nw project.nw" -// /tmp/.org.chromium.Chromium.RQPJgQ if run as packaged executable -var execName = path.basename(process.execPath); -// TODO Mac OS binary name? -if (execName !== "nw" && execName !== "nw.exe") { - // Run as direct executable - appDir = path.dirname(process.execPath); -} - -console.log("Working directory:", appDir); - - -var app = require("json-server"); - -// Override serveStatic middleware -var serveStatic = require("json-server/node_modules/serve-static"); -var RouterLayer = require("json-server/node_modules/express/lib/router/layer"); -var indexOfMiddleware = 0; -while (indexOfMiddleware < app._router.stack.length && app._router.stack[indexOfMiddleware].name !== "serveStatic") { - indexOfMiddleware++; -} -if (indexOfMiddleware < app._router.stack.length) { - app._router.stack[indexOfMiddleware] = new RouterLayer("/", { - "sensitive": app._router.caseSensitive, - "strict": false, - "end": false - }, serveStatic(path.resolve(appDir, "public"))); - console.log("Serve static directory:", path.resolve(appDir, "public")); -} - -// DB file -app.low.path = path.resolve(appDir, "db.json"); -if (!fs.existsSync(app.low.path)) { - fs.writeFileSync(app.low.path, "{}"); -} -app.low.db = require(app.low.path); - -// Now the real HTTP server -var server = http.createServer(app); -app.port = process.env.PORT || 26080; - -server.listen(app.port); - -server.on("listening", function () { - console.log("Server ready:", this.address()); -}); - -// Emit on each request -function ping (name, req) { - if (req.method !== "GET") { - setTimeout(function () { - process.emit("data-update"); - }, 100); - } - process.emit("request", req.method, req.url, req.body); -} +const jsonServer = require('json-server'); +const path = require('path'); +const fs = require('fs'); +const _ = require('lodash'); +const is = require('./utils/is'); +const chalk = require('chalk'); +const morgan = require("morgan"); +const server = jsonServer.create(); +const middlewares = jsonServer.defaults(); + +process.chdir(path.dirname(process.execPath)); + +// Get current directory +var appDir = process.env.APP_DIR || process.cwd(); +// Get execPath +// /path/to/nw if run as "nw project.nw" +// /tmp/.org.chromium.Chromium.RQPJgQ if run as packaged executable +var execName = path.basename(process.execPath); +// TODO Mac OS binary name? +if (execName !== "nw" && execName !== "nw.exe") { + // Run as direct executable + appDir = path.dirname(process.execPath); +} + +var configPath = path.resolve(appDir, "config/config.json"); +var configFolderPath = path.resolve(appDir, "config"); +if (!fs.existsSync(configPath)) +{ + if (!fs.existsSync(configFolderPath)) + { + fs.mkdirSync(configFolderPath); + } + fs.writeFileSync(configPath, "{}"); +} +var config = JSON.parse(fs.readFileSync(configPath)); +if (config.DataPath != null) +{ + var rootDir = path.resolve(config.DataPath) || process.cwd(); +} +else +{ + var rootDir = process.env.APP_DIR || process.cwd(); +} + + +console.log("Working directory:", rootDir); + +var dbPath = path.resolve(rootDir, "db.json"); +if (!fs.existsSync(dbPath)) +{ + fs.writeFileSync(dbPath, "{}"); +} + +var router = jsonServer.router(dbPath); +var port = config.Port || process.env.PORT || 26080; + +middlewares.push(morgan('dev', { + skip: function(req, res) { process.emit("request", req.method, req.originalUrl, req.body); return false; } +})); + +server.use(middlewares); +server.use(router); + +fs.watch(rootDir, (event, file) => { + if (file) + { + const watchedFile = path.resolve(rootDir, file); + if (watchedFile == path.resolve(dbPath)) + { + if (is.JSON(watchedFile)) + { + let obj; + try + { + obj = JSON.parse(fs.readFileSync(watchedFile)); + } + catch (e) + { + console.log(chalk.red(` Error reading ${watchedFile}`)); + console.error(e.message); + return; + } + + const isDatabaseDifferent = !_.isEqual(obj, router.db.getState()); + if (isDatabaseDifferent) + { + console.log(chalk.grey(` ${dbPath} has changed, reloading...`)); + router.db.read(); + process.emit("data-update"); + } + } + } + } +}); + +server.use((req, res, next) => { + process.emit("request", req.method, req.originalUrl, req.body); + next(); +}); + +var serverProcess; + +server.on("listening", function () { + console.log("Server ready:", this.address()); +}); + +function stop_server() +{ + serverProcess && serverProcess.close(); + conn("Server stopped"); +} + +function start_server() +{ + conn("Connecting"); + serverProcess = server.listen(port, () => { + console.log("JSON Server is running"); + conn("Online"); + }); +} \ No newline at end of file diff --git a/src/utils/is.js b/src/utils/is.js new file mode 100644 index 0000000..e367e26 --- /dev/null +++ b/src/utils/is.js @@ -0,0 +1,21 @@ +/** + * This file is a copy from json-server's 'utils/is.js' file. + */ + +module.exports = { + JSON, + JS, + URL +} + +function JSON(s) { + return !URL(s) && /\.json$/.test(s) +} + +function JS(s) { + return !URL(s) && /\.js$/.test(s) +} + +function URL(s) { + return /^(http|https):/.test(s) +} \ No newline at end of file