This repository has been archived by the owner on Dec 16, 2020. It is now read-only.
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 6b82af6
Showing
15 changed files
with
7,320 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
### Node template | ||
# Logs | ||
logs | ||
*.log | ||
npm-debug.log* | ||
yarn-debug.log* | ||
yarn-error.log* | ||
|
||
# Runtime data | ||
pids | ||
*.pid | ||
*.seed | ||
*.pid.lock | ||
|
||
# Directory for instrumented libs generated by jscoverage/JSCover | ||
lib-cov | ||
|
||
# Coverage directory used by tools like istanbul | ||
coverage | ||
|
||
# nyc test coverage | ||
.nyc_output | ||
|
||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) | ||
.grunt | ||
|
||
# Bower dependency directory (https://bower.io/) | ||
bower_components | ||
|
||
# node-waf configuration | ||
.lock-wscript | ||
|
||
# Compiled binary addons (https://nodejs.org/api/addons.html) | ||
build/Release | ||
|
||
# Dependency directories | ||
node_modules/ | ||
jspm_packages/ | ||
|
||
# TypeScript v1 declaration files | ||
typings/ | ||
|
||
# Optional npm cache directory | ||
.npm | ||
|
||
# Optional eslint cache | ||
.eslintcache | ||
|
||
# Optional REPL history | ||
.node_repl_history | ||
|
||
# Output of 'npm pack' | ||
*.tgz | ||
|
||
# Yarn Integrity file | ||
.yarn-integrity | ||
|
||
# dotenv environment variables file | ||
.env | ||
|
||
# parcel-bundler cache (https://parceljs.org/) | ||
.cache | ||
|
||
# next.js build output | ||
.next | ||
|
||
# nuxt.js build output | ||
.nuxt | ||
|
||
# Nuxt generate | ||
dist | ||
|
||
# vuepress build output | ||
.vuepress/dist | ||
|
||
# Serverless directories | ||
.serverless | ||
|
||
# IDE | ||
.idea |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
# nuxt-services | ||
|
||
> Example of services features for Nuxt 3. | ||
## Setup | ||
|
||
``` | ||
yarn install | ||
``` | ||
|
||
Make sure to have [MongoDB](https://www.mongodb.com) installed and running on your machine. | ||
|
||
## Development | ||
|
||
``` | ||
yarn dev | ||
``` | ||
|
||
## Production | ||
|
||
``` | ||
yarn build | ||
yarn start | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<title></title> | ||
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> | ||
</head> | ||
<body> | ||
<div id="app"><button @click="test">Test</button></div> | ||
<script> | ||
class ClientRPC { | ||
constructor(remote) { | ||
this.ws = new WebSocket(`ws://${remote}/`); | ||
this.challenge = 0; | ||
this.returns = new Map(); | ||
this.connected = false; | ||
|
||
this.ws.onmessage = (data) => { | ||
|
||
try { | ||
var obj = JSON.parse(data.data); | ||
} catch(e) { | ||
console.log("Err", e, data.data); | ||
return; | ||
} | ||
|
||
switch (obj.action ) { | ||
case "return": | ||
|
||
if (obj.challenge && obj.action) { | ||
const resolve = this.returns.get(obj.challenge); | ||
|
||
resolve(obj.data); | ||
this.returns.delete(obj.challenge) | ||
} | ||
break; | ||
default: | ||
} | ||
|
||
} | ||
|
||
this.ws.onopen = () => { | ||
this.connected = true; | ||
} | ||
|
||
this.ws.onclose = () => { | ||
this.connected = false; | ||
} | ||
} | ||
|
||
callMethod(name, ...args) { | ||
if (!this.connected) { | ||
console.log('WS not connected, retrying in a sec...') | ||
return new Promise((resolve) => setTimeout(() => this.callMethod(name, ...args), 1000)); | ||
} | ||
|
||
const payload = { | ||
action: "call", | ||
method: name, | ||
args: args, | ||
challenge: ++this.challenge | ||
} | ||
|
||
const ret = new Promise((resolve, reject) => { | ||
this.returns.set(this.challenge, resolve); | ||
}); | ||
|
||
this.ws.send(JSON.stringify(payload)); | ||
|
||
return ret; | ||
} | ||
} | ||
|
||
|
||
new Vue({ | ||
el: '#app', | ||
data() { | ||
return { | ||
rpc: new ClientRPC('127.0.0.1:8081') | ||
} | ||
}, | ||
beforeMount() { | ||
this.test() | ||
}, | ||
methods: { | ||
async test() { | ||
const ret = await this.rpc.callMethod("testCall", 42, "foo"); | ||
console.log("RPC received", ret); | ||
console.log(this.rpc.returns); | ||
} | ||
} | ||
}) | ||
|
||
</script> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import consola from 'consola' | ||
import { MongoClient, ObjectID } from 'mongodb' | ||
|
||
export default async function (options) { | ||
const mongodb = Object.assign({}, options, this.options.mongodb) | ||
|
||
if (!mongodb) throw new Error('No `mongodb` configuration found') | ||
if (!mongodb.url) throw new Error('No `mongodb.url` configuration found') | ||
if (!mongodb.dbName) throw new Error('No `mongodb.dbName` configuration found') | ||
|
||
// Defaults | ||
mongodb.findLimitDefault = mongodb.findLimitDefault || 20 | ||
mongodb.findLimitMax = mongodb.findLimitMax || 100 | ||
|
||
consola.info(`Connecting to ${mongodb.url}...`) | ||
const client = await MongoClient.connect(mongodb.url, { useNewUrlParser: true, ...mongodb.options }) | ||
const db = client.db(mongodb.dbName) | ||
consola.info(`Connected to ${mongodb.dbName} database`) | ||
|
||
this.nuxt.$db = db; | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
import { resolve, join } from 'path' | ||
import { promisify } from 'util' | ||
import devalue from '@nuxtjs/devalue' | ||
import WebSocket from 'ws' | ||
|
||
const glob = promisify(require('glob')) | ||
|
||
export default async function() { | ||
/* | ||
* Fetch services | ||
*/ | ||
const servicesPath = resolve(this.options.srcDir, 'services') | ||
const files = await glob(join(servicesPath, '/**/*.js')) | ||
this.options.watch = this.options.watch.concat(files) | ||
const services = {} | ||
const servicesMap = {} | ||
|
||
files.map(path => { | ||
const serviceKey = path | ||
.replace(servicesPath, '') | ||
.replace(/^\//, '') | ||
.replace(/\.js$/, '') | ||
const keys = serviceKey.split('/') | ||
const service = this.nuxt.resolver.requireModule(path) || {} | ||
// TODO: Use class instead, and have this.context | ||
Object.keys(service).forEach((method) => { | ||
if (typeof service[method] === 'function') | ||
service[method] = service[method].bind(this.nuxt) | ||
}) | ||
|
||
servicesMap[serviceKey] = Object.keys(service) | ||
|
||
let s = services | ||
keys.forEach((key, i) => { | ||
if (i + 1 < keys.length) { | ||
s[key] = s[key] || {} | ||
s = s[key] | ||
return | ||
} | ||
s[key] = service | ||
}) | ||
}) | ||
/* | ||
** Add plugin | ||
*/ | ||
const url = `ws://${this.options.server.host}:${this.options.server.port}` | ||
this.addPlugin({ | ||
filename: 'services.ws.client.js', | ||
src: join(__dirname, 'plugin.client.js'), | ||
ssr: false, | ||
options: { | ||
url, | ||
servicesMap | ||
} | ||
}) | ||
this.addPlugin({ | ||
filename: 'services.ws.server.js', | ||
src: join(__dirname, 'plugin.server.js') | ||
}) | ||
this.addServerMiddleware((req, res, next) => { | ||
req.services = services | ||
next() | ||
}) | ||
/* | ||
** Create WS server | ||
*/ | ||
this.nuxt.hook('listen', server => { | ||
const wss = new WebSocket.Server({ server }) | ||
|
||
wss.on('connection', ws => { | ||
ws.services = services | ||
|
||
ws.on('error', err => Consola.error(err)) | ||
|
||
ws.on('message', async msg => { | ||
let obj | ||
try { | ||
obj = (0,eval)(`(${msg})`) | ||
} catch (e) { | ||
return // Ignore it | ||
} | ||
if (typeof obj.challenge === 'undefined') | ||
return consola.error('No challenge given to', obj) | ||
|
||
let data = null | ||
let error = null | ||
|
||
switch (obj.action) { | ||
case 'call': | ||
try { | ||
let serviceModule = ws.services | ||
obj.module.split('/').forEach((m) => serviceModule = serviceModule[m]) | ||
data = await serviceModule[obj.method].call(this.nuxt, ...obj.args) | ||
} catch (e) { | ||
error = JSON.parse(JSON.stringify(e, Object.getOwnPropertyNames(e))) | ||
if (!this.options.dev) delete error.stack | ||
} | ||
break | ||
default: | ||
} | ||
|
||
const payload = { | ||
action: 'return', | ||
challenge: obj.challenge || 0, | ||
data, | ||
error | ||
} | ||
|
||
ws.send(devalue(payload)) | ||
}) | ||
}) | ||
consola.info('Websockets server ready for services') | ||
}) | ||
} |
Oops, something went wrong.