Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
pi0 committed Jul 6, 2021
0 parents commit a5b6b7f
Show file tree
Hide file tree
Showing 11 changed files with 4,186 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"extends": [
"@nuxtjs/eslint-config-typescript"
]
}
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules
*.log*
dist
77 changes: 77 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# 🥭 mongoz

> Ad hoc MongoDB server for Node.js
## Why?

[MongoDB](https://www.mongodb.com) is fantastic but setup for small projects can be lots of trouble.

This little package does everything necessary to download and start a fresh mongo server!

## Usage

**Note:** You need to have [Node.js](https://nodejs.org/en/) and [npm](https://docs.npmjs.com/cli/v7/commands/npm) already installed!

**Note:** Make sure there is not already a local mongodb server listening on default port (`2701`). If you do, either stop it or use `PORT` environment variable to change the port.

### Standalone Server

Let's start a fresh mongoz shall we?

```sh
npx mongoz
```

It will take few seconds on first time of usage to install and extract mongo server.

### Programmatic Usage

Do you need a MongoDB server? No problems!

```js
// CommonJS
const { startMongo } = require('mongoz')

// ESM
import { startMongo } from 'mongoz'

// Install and start listening MongoDB on 127.0.0.1:27017 in background
await startMongo()
```

When closing server, mongo will also gracefully shutdown with [node-graceful-shutdown](https://www.npmjs.com/package/node-graceful-shutdown).

### In parallel with server

You can also use [concurrently](https://www.npmjs.com/package/concurrently) to start mongo alongside with server:

`package.json`:

```json
{
"scripts": {
"start": "concurrently 'npx mongoz' 'node ./server.mjs'"
}
}
```

Or directly with `npx`:

```sh
npx concurrently 'npx mongoz' 'node ./server.mjs'
```

## Supported platforms

Windows, Linux and Darwin (Mac) are supported. Check [formula](./src/formula) for details.

## Changing data dir

By default, we use a temporary directory to store data and logs. You can customize it with `MONGO_DIR` environment variable.

## License

MIT.

See [MongoDB Licensing](https://www.mongodb.com/community/licensing) for underlying server license.

3 changes: 3 additions & 0 deletions bin/mongoz
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/usr/bin/env node

require('../dist/cli')
10 changes: 10 additions & 0 deletions build.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { defineBuildConfig } from 'unbuild'

export default defineBuildConfig({
declaration: true,
entries: [
'./src/cli',
'./src/index'
],
inlineDependencies: true
})
39 changes: 39 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"name": "mongoz",
"version": "0.0.0",
"repository": "unjs/mongoz",
"license": "MIT",
"main": "./dist/index.js",
"exports": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"bin": "./bin/mongoz",
"files": [
"dist",
"bin"
],
"scripts": {
"lint": "eslint --ext .ts,.js",
"prepack": "unbuild",
"dev": "jiti ./src/cli.ts",
"start": "npx concurrently 'yarn dev' 'node server.mjs'",
"release": "yarn test && standard-version && git push --follow-tags && npm publish",
"test": "yarn lint"
},
"dependencies": {
"download": "^8.0.0",
"ora": "^5.4.1",
"decompress": "^4.2.1",
"consola": "^2.15.3",
"fs-extra": "^10.0.0",
"node-graceful-shutdown": "^1.1.0"
},
"devDependencies": {
"@nuxtjs/eslint-config-typescript": "^6.0.1",
"eslint": "^7.30.0",
"execa": "^5.1.1",
"jiti": "^1.10.1",
"standard-version": "^9.3.0",
"typescript": "^4.3.5",
"unbuild": "^0.3.1"
}
}
11 changes: 11 additions & 0 deletions src/cli.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { startMongo } from './index'

async function main() {
const args = process.argv.splice(2)
const mongoserver = await startMongo({ args })
}

main().catch(err => {
console.error(err)
process.exit(1)
})
21 changes: 21 additions & 0 deletions src/formula.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
export const mongoFormula = {
name: 'mongo',
version: '4.4.2',
port: 27017,
exec: 'bin/mongod',
execArgs: '--port {port} --dbpath {data}',
platforms: [
{
name: 'linux',
source: 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-ubuntu2004-4.4.2.tgz'
},
{
name: 'win32',
source: 'https://fastdl.mongodb.org/windows/mongodb-windows-x86_64-4.4.2.zip'
},
{
name: 'darwin',
source: 'https://fastdl.mongodb.org/osx/mongodb-macos-x86_64-4.4.2.tgz'
}
]
}
84 changes: 84 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import path from 'path'
import os from 'os'
import fsExtra from 'fs-extra'
import download from 'download'
import consola from 'consola'
import decompress from 'decompress'
import execa from 'execa'
import ora from 'ora'
import { onShutdown } from 'node-graceful-shutdown'
import { mongoFormula as formula } from './formula'

export async function startMongo (opts = { args: null }) {
const platformName = process.platform
let platform = formula.platforms.find(p => p.name === platformName)
if (!platform) {
throw new Error(`Platform '${platformName}' is not available for '${formula.name}'`)
}

const instanceName = 'default'
const appDir = process.env.MONGO_DIR || path.resolve(os.tmpdir(), formula.name)

// Resolve paths
const dataDir = path.resolve(appDir, 'data', instanceName, formula.name)
const logsDir = path.resolve(appDir, 'logs', instanceName, formula.name)
const logFile = path.resolve(logsDir, 'logs.txt')
const sourceDir = path.resolve(appDir, 'source', formula.name, formula.version, platform.name)
const sourceFileName = `${formula.name}-${formula.version}-${platform.name}` + path.extname(platform.source)
const sourceFile = path.resolve(sourceDir, sourceFileName)
const extractDir = path.resolve(sourceDir, 'unpacked')
const execFile = path.resolve(extractDir, formula.exec)

// Ensure data dir exists
await fsExtra.mkdirp(dataDir)

// Show a spinner
const spinner = ora()

// Ensure package is installed
if (!fsExtra.existsSync(extractDir) || !fsExtra.existsSync(execFile)) {
if (!fsExtra.existsSync(sourceFile)) {
const dlMessage = `Downloading ${sourceFileName}`
spinner.start(dlMessage + '...')
const res = download(platform.source, sourceDir, { filename: sourceFileName })
res.on('downloadProgress', (e) => {
spinner.text = `${dlMessage} | ${Math.round(e.percent * 100)}%`
})
await res
}
spinner.start(`Decompressing ${sourceFileName}...`)
await decompress(sourceFile, extractDir, { strip: 1 })
spinner.stop()
}
await fsExtra.mkdirp(logsDir)
await fsExtra.remove(logFile)

// Open logs file
let stdout, stderr
const logsFile = await fsExtra.open(logFile, 'w+')
stdout = stderr = logsFile
consola.info(`Writing logs to: ${logFile}`)

// Port and args
const port = process.env.PORT || formula.port
const execArgs = formula.execArgs.replace('{port}', port + '').replace('{data}', dataDir).split(' ')
if (Array.isArray(opts.args)) {
execArgs.push(...opts.args)
}

// Start app
spinner.info(`Starting ${formula.name} at port ${port}`)
const server = execa(execFile, execArgs, {
stdout,
stderr
})

const close = () => Promise.resolve(server.cancel())

onShutdown(() => close())

return {
server,
close
}
}
6 changes: 6 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"compilerOptions": {
"moduleResolution": "Node",
"esModuleInterop": true
},
}
Loading

0 comments on commit a5b6b7f

Please sign in to comment.