Skip to content

Commit

Permalink
Merge pull request #22 from malijs/mutli_proto
Browse files Browse the repository at this point in the history
Add support for mutli proto servers
  • Loading branch information
bojand committed Dec 29, 2017
2 parents a5b78d4 + 516b4a0 commit 7dbc160
Show file tree
Hide file tree
Showing 5 changed files with 591 additions and 221 deletions.
17 changes: 10 additions & 7 deletions API.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ Represents a gRPC service
* [.name](#Maliname) : <code>String</code>
* [.env](#Malienv) : <code>String</code>
* [.ports](#Maliports) : <code>Array</code>
* [.init(proto, name, options)](#Maliinit)
* [.addService(proto, name, options)](#MaliaddService)
* [.use(service, name, ...fns)](#Maliuse)
* [.onerror(err)](#Malionerror)
* [.start(port, creds)](#Malistart) ⇒ <code>Object</code>
Expand Down Expand Up @@ -74,7 +74,8 @@ Whether to log errors in <code>onerror</code>. Default: <code>false</code>
<a name="maliname" id="maliname" data-id="maliname"></a>

#### mali.name : <code>String</code>
The service name
The service name.
If multiple services are initalized, this will be equal to the first service loaded.

**Kind**: instance property of [<code>Mali</code>](#Mali)
**Example**
Expand Down Expand Up @@ -107,11 +108,12 @@ The ports of the started service(s)
console.log(app.ports) // [ 52239 ]
```

<a name="maliinit" id="maliinit" data-id="maliinit"></a>
<a name="maliaddservice" id="maliaddservice" data-id="maliaddservice"></a>

#### mali.init(proto, name, options)
Init's the app with the proto. Basically this can be used if you don't have the data at
app construction time for some reason.
#### mali.addService(proto, name, options)
Add the service and initalizes the app with the proto.
Basically this can be used if you don't have the data at app construction time for some reason.
This is different than `grpc.Server.addService()`.

**Kind**: instance method of [<code>Mali</code>](#Mali)

Expand All @@ -135,7 +137,8 @@ name. Uses <code>0</code>th property in internal services object. Useful for pro
one service.
If an <code>object</code> is provided, you can set middleware and handlers for all services.
If <code>object</code> provided but <code>0</code>th key does not match any of the services in
proto, assumes <code>0</code>th service. Useful for protos with only one service.
proto, we try to match the key to one of the rpc function names in one of the services.
if we can't find the matching rpc function name just tries the `0`th service name.

**Kind**: instance method of [<code>Mali</code>](#Mali)

Expand Down
62 changes: 42 additions & 20 deletions lib/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,19 +48,22 @@ class Mali extends Emitter {
this.handlers = {} // specific middleware and handlers
this.servers = []
this.ports = []
this.services = {}
this.methods = {}

// app options / settings
this.context = new Context()
this.env = process.env.NODE_ENV || 'development'

if (path) {
this.init(path, name, options)
this.addService(path, name, options)
}
}

/**
* Init's the app with the proto. Basically this can be used if you don't have the data at
* app construction time for some reason.
* Add the service and initalizes the app with the proto.
* Basically this can be used if you don't have the data at app construction time for some reason.
* This is different than `grpc.Server.addService()`.
* @param {String|Object} proto - Path to the protocol buffer definition file
* - Object specifying <code>root</code> directory and <code>file</code> to load
* - Loaded grpc object
Expand All @@ -70,15 +73,12 @@ class Mali extends Emitter {
* In case of proto object the name of the constructor.
* @param {Object} options - Options to be passed to <code>grpc.load</code>
*/
init (path, name, options) {
this.name = name
this.load = _.isString(path) || (_.isObject(path) && path.root && path.file)
this.proto = this.load ? this.grpc.load(path, undefined, options) : path
addService (path, name, options) {
const load = _.isString(path) || (_.isObject(path) && path.root && path.file)
const proto = load ? this.grpc.load(path, undefined, options) : path

this.services = {}
this.methods = {}
if (this.load || !mu.isStaticGRPCObject(this.proto)) {
let descriptor = gi(this.proto)
if (load || !mu.isStaticGRPCObject(proto)) {
let descriptor = gi(proto)
let names = descriptor.serviceNames()
if (_.isString(name)) {
names = [name]
Expand All @@ -96,22 +96,30 @@ class Mali extends Emitter {
this.methods[n] = mu.getMethodDescriptorsLoad(n, service, descriptor)
}
})
} else if (_.isObject(this.proto)) {
let names = _.keys(this.proto)
} else if (_.isObject(proto)) {
let names = _.keys(proto)
if (_.isString(name)) {
names = [name]
} else if (_.isArray(name)) {
names = _.intersection(name, names)
}

_.forOwn(this.proto, (v, n) => {
_.forOwn(proto, (v, n) => {
if (_.isObject(v) && !_.isFunction(v) && names.indexOf(n) >= 0) {
this.services[n] = v
this.middleware[n] = []
this.methods[n] = mu.getMethodDescriptorsProto(n, v)
}
})
}

if (!this.name) {
if (name && _.isString(name)) {
this.name = name
} else {
this.name = _.keys(this.services)[0]
}
}
}

/**
Expand All @@ -126,7 +134,8 @@ class Mali extends Emitter {
* one service.
* If an <code>object</code> is provided, you can set middleware and handlers for all services.
* If <code>object</code> provided but <code>0</code>th key does not match any of the services in
* proto, assumes <code>0</code>th service. Useful for protos with only one service.
* proto, we try to match the key to one of the rpc function names in one of the services.
* if we can't find the matching rpc function name just tries the `0`th service name.
* @param {String|Object} service Service name
* @param {String|Function} name RPC name
* @param {Function|Array} fns - Middleware and/or handler
Expand Down Expand Up @@ -171,8 +180,20 @@ class Mali extends Emitter {
} else if (_.isPlainObject(service)) {
const testKey = _.keys(service)[0]
if (_.isFunction(service[testKey]) || _.isArray(service[testKey])) {
const serviceName = _.keys(this.services)[0]
_.forOwn(service, (mw, mwName) => {
let serviceName
_.forOwn(this.services, (sd, sn) => {
if (!serviceName) {
const serviceFunctions = _.keys(sd)
if (serviceFunctions.indexOf(mwName) >= 0) {
serviceName = sn
}
}
})
if (!serviceName) {
serviceName = _.keys(this.services)[0]
}

if (_.isFunction(mw)) {
this.use(serviceName, mwName, mw)
} else {
Expand Down Expand Up @@ -330,7 +351,8 @@ class Mali extends Emitter {
}

/**
* @member {String} name The service name
* @member {String} name The service name.
* If multiple services are initalized, this will be equal to the first service loaded.
* @memberof Mali#
* @example
* console.log(app.name) // 'Greeter'
Expand All @@ -355,9 +377,9 @@ class Mali extends Emitter {
* @memberof Mali#
*/

/*!
* Internal create context
*/
/*!
* Internal create context
*/
_createContext (call, descriptor) {
const type = mu.getCallTypeFromCall(call) || mu.getCallTypeFromDescriptor(descriptor)
const { name, fullName, service } = descriptor
Expand Down

0 comments on commit 7dbc160

Please sign in to comment.