This repository has been archived by the owner on Feb 8, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 83
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Welcome Gitter to Broid family (#48)
- Loading branch information
Showing
25 changed files
with
5,129 additions
and
0 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
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,243 @@ | ||
[![npm][npm]][npm-url] | ||
[![node][node]][node-url] | ||
[![deps][deps]][deps-url] | ||
[![tests][tests]][tests-url] | ||
[![bithound][bithound]][bithound-url] | ||
[![bithoundscore][bithoundscore]][bithoundscore-url] | ||
[![nsp-checked][nsp-checked]][nsp-checked-url] | ||
|
||
# Broid Gitter Integration | ||
|
||
Broid Integrations is an open source project providing a suite of Activity Streams 2 libraries for unified communications among a vast number of communication platforms. | ||
|
||
> Connect your App to Multiple Messaging Channels with One OpenSource Language. | ||
[![gitter](https://badges.gitter.im/broidHQ/broid.svg)](https://t.broid.ai/c/Blwjlw?utm_source=github&utm_medium=readme&utm_campaign=top&link=gitter) | ||
|
||
## Getting started | ||
|
||
### Install | ||
|
||
```bash | ||
npm install --save broid-gitter | ||
``` | ||
|
||
### Connect to Gitter | ||
|
||
```javascript | ||
import broidGitter from 'broid-gitter' | ||
|
||
const gitter = new broidGitter({ | ||
token: '<your_action_name_here>' | ||
}) | ||
|
||
gitter.connect() | ||
.subscribe({ | ||
next: data => console.log(data), | ||
error: err => console.error(`Something went wrong: ${err.message}`), | ||
complete: () => console.log('complete'), | ||
}) | ||
``` | ||
|
||
**Options availables** | ||
|
||
| name | Type | default | Description | | ||
| --------------- |:--------:| :--------: | --------------------------| | ||
| serviceID | string | random | Arbitrary identifier of the running instance | | ||
| logLevel | string | `info` | Can be : `fatal`, `error`, `warn`, `info`, `debug`, `trace` | | ||
| token | string | | Gitter token. | | ||
|
||
### Receive a message | ||
|
||
```javascript | ||
gitter.listen() | ||
.subscribe({ | ||
next: data => console.log(`Received message: ${data}`), | ||
error: err => console.error(`Something went wrong: ${err.message}`), | ||
complete: () => console.log('complete'), | ||
}) | ||
``` | ||
|
||
### Post a message | ||
|
||
To send a message, the format should use the [broid-schemas](https://github.com/broidhq/broid-schemas). | ||
|
||
```javascript | ||
const message_formated = '...' | ||
|
||
gitter.send(message_formated) | ||
.then(() => console.log("ok")) | ||
.catch(err => console.error(err)) | ||
``` | ||
|
||
## Examples of messages | ||
|
||
### Message received | ||
|
||
- A message received from Sally | ||
|
||
```json | ||
{ | ||
"@context": "https://www.w3.org/ns/activitystreams", | ||
"published": 1483677146, | ||
"type": "Create", | ||
"generator": { | ||
"id": "67c9cb10-8a74-42c8-ba55-294d0447cdf9", | ||
"type": "Service", | ||
"name": "gitter" | ||
}, | ||
"actor": { | ||
"id": "588f9929d73402ce4f470489", | ||
"name": "Sally", | ||
"type": "Person" | ||
}, | ||
"target": { | ||
"id": "588f9929d73402ce4f470489", | ||
"type": "Group", | ||
"name": "Broid/test" | ||
}, | ||
"object": { | ||
"type": "Note", | ||
"id": "5897bfbbaa800ee52c57be39", | ||
"content": "Hello world" | ||
} | ||
} | ||
``` | ||
|
||
- A private message received from Sally | ||
|
||
```json | ||
{ | ||
"@context": "https://www.w3.org/ns/activitystreams", | ||
"published": 1483677146, | ||
"type": "Create", | ||
"generator": { | ||
"id": "67c9cb10-8a74-42c8-ba55-294d0447cdf9", | ||
"type": "Service", | ||
"name": "gitter" | ||
}, | ||
"actor": { | ||
"id": "588f9929d73402ce4f470489", | ||
"name": "Sally", | ||
"type": "Person" | ||
}, | ||
"target": { | ||
"id": "588f9929d73402ce4f470489", | ||
"name": "Sally", | ||
"type": "Person" | ||
}, | ||
"object": { | ||
"type": "Note", | ||
"id": "5897bfbbaa800ee52c57be39", | ||
"content": "Hello world" | ||
} | ||
} | ||
``` | ||
|
||
### Send a message | ||
|
||
- Send a simple message | ||
|
||
```json | ||
{ | ||
"@context": "https://www.w3.org/ns/activitystreams", | ||
"type": "Create", | ||
"generator": { | ||
"id": "f6e92eb6-f69e-4eae-8158-06613461cf3a", | ||
"type": "Service", | ||
"name": "gitter" | ||
}, | ||
"object": { | ||
"type": "Note", | ||
"content": "hello world" | ||
}, | ||
"to": { | ||
"id": "588f9929d73402ce4f470489", | ||
"type": "Group" | ||
} | ||
} | ||
``` | ||
|
||
- Send a simple private message | ||
|
||
```json | ||
{ | ||
"@context": "https://www.w3.org/ns/activitystreams", | ||
"type": "Create", | ||
"generator": { | ||
"id": "f6e92eb6-f69e-4eae-8158-06613461cf3a", | ||
"type": "Service", | ||
"name": "gitter" | ||
}, | ||
"object": { | ||
"type": "Note", | ||
"content": "hello world" | ||
}, | ||
"to": { | ||
"id": "588f9929d73352ce4f470489", | ||
"type": "Person" | ||
} | ||
} | ||
``` | ||
|
||
- Edit a message | ||
|
||
```json | ||
{ | ||
"@context": "https://www.w3.org/ns/activitystreams", | ||
"type": "Create", | ||
"generator": { | ||
"id": "f6e92eb6-f69e-4eae-8158-06613461cf3a", | ||
"type": "Service", | ||
"name": "gitter" | ||
}, | ||
"object": { | ||
"id": "548f9929d73352ce4f470499", | ||
"type": "Note", | ||
"content": "hello world" | ||
}, | ||
"to": { | ||
"id": "588f9929d73402ce4f470489", | ||
"type": "Person" | ||
} | ||
} | ||
``` | ||
|
||
# Contributing to Broid | ||
|
||
Broid is an open source project. Broid wouldn't be where it is now without contributions by the community. Please consider forking Broid to improve, enhance or fix issues. If you feel like the community will benefit from your fork, please open a pull request. | ||
|
||
And because we want to do the better for you. Help us improving Broid by | ||
sharing your feedback on our [Integrations GitHub Repo](https://github.com/broidhq/integrations) and let's build Broid together! | ||
|
||
## Code of Conduct | ||
|
||
Make sure that you're read and understand the [Code of Conduct](http://contributor-covenant.org/version/1/2/0/). | ||
|
||
## Copyright & License | ||
|
||
Copyright (c) 2016-2017 Broid.ai | ||
|
||
This project is licensed under the AGPL 3, which can be | ||
[found here](https://www.gnu.org/licenses/agpl-3.0.en.html). | ||
|
||
[npm]: https://img.shields.io/badge/npm-broid-green.svg?style=flat | ||
[npm-url]: https://www.npmjs.com/~broid | ||
|
||
[node]: https://img.shields.io/node/v/broid-slack.svg | ||
[node-url]: https://nodejs.org | ||
|
||
[deps]: https://img.shields.io/badge/dependencies-checked-green.svg?style=flat | ||
[deps-url]: #integrations | ||
|
||
[tests]: https://img.shields.io/travis/broidHQ/integrations/master.svg | ||
[tests-url]: https://travis-ci.org/broidHQ/integrations | ||
|
||
[bithound]: https://img.shields.io/bithound/code/github/broidHQ/integrations.svg | ||
[bithound-url]: https://www.bithound.io/github/broidHQ/integrations | ||
|
||
[bithoundscore]: https://www.bithound.io/github/broidHQ/integrations/badges/score.svg | ||
[bithoundscore-url]: https://www.bithound.io/github/broidHQ/integrations | ||
|
||
[nsp-checked]: https://img.shields.io/badge/nsp-checked-green.svg?style=flat | ||
[nsp-checked-url]: https://nodesecurity.io |
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,140 @@ | ||
"use strict"; | ||
const Promise = require("bluebird"); | ||
const broid_schemas_1 = require("broid-schemas"); | ||
const broid_utils_1 = require("broid-utils"); | ||
const events_1 = require("events"); | ||
const Gitter = require("node-gitter"); | ||
const uuid = require("node-uuid"); | ||
const R = require("ramda"); | ||
const Rx_1 = require("rxjs/Rx"); | ||
const parser_1 = require("./parser"); | ||
const eventNames = ["chatMessages"]; | ||
const roomToInfos = (room) => ({ | ||
id: room.id, | ||
name: room.name, | ||
oneToOne: room.oneToOne, | ||
uri: room.uri, | ||
url: room.url, | ||
}); | ||
class Adapter { | ||
constructor(obj) { | ||
this.serviceID = obj && obj.serviceID || uuid.v4(); | ||
this.logLevel = obj && obj.logLevel || "info"; | ||
this.token = obj && obj.token || null; | ||
this.ee = new events_1.EventEmitter(); | ||
this.parser = new parser_1.default(this.serviceID, this.logLevel); | ||
this.logger = new broid_utils_1.Logger("adapter", this.logLevel); | ||
} | ||
users() { | ||
return Promise.reject(new Error("Not supported")); | ||
} | ||
channels() { | ||
return new Promise((resolve, reject) => { | ||
return this.session.rooms.findAll() | ||
.then(resolve) | ||
.catch(reject); | ||
}) | ||
.map(roomToInfos); | ||
} | ||
serviceId() { | ||
return this.serviceID; | ||
} | ||
connect() { | ||
if (!this.token || this.token === "") { | ||
return Rx_1.Observable.throw(new Error("Token should exist.")); | ||
} | ||
this.session = new Gitter(this.token); | ||
const handler = (room, eventName) => { | ||
return (data) => { | ||
if (data.operation === "create" | ||
&& this.me.username !== R.path(["model", "fromUser", "username"], data)) { | ||
return this.ee.emit(eventName, { | ||
data: data.model, | ||
room: roomToInfos(room), | ||
}); | ||
} | ||
return null; | ||
}; | ||
}; | ||
const currentUser = new Promise((resolve, reject) => this.session.currentUser() | ||
.then(resolve) | ||
.catch(reject)); | ||
const connect = currentUser | ||
.tap((user) => this.me = user) | ||
.then(() => this.channels()) | ||
.map((room) => this.joinRoom(room)) | ||
.map((room) => { | ||
room.subscribe(); | ||
R.forEach((eventName) => room.on(eventName, handler(room, eventName)), eventNames); | ||
return room; | ||
}); | ||
return Rx_1.Observable.fromPromise(connect) | ||
.map(() => ({ type: "connected", serviceID: this.serviceId() })); | ||
} | ||
disconnect() { | ||
return Promise.reject(new Error("Not supported")); | ||
} | ||
listen() { | ||
if (!this.session) { | ||
return Rx_1.Observable.throw(new Error("No session found.")); | ||
} | ||
const fromEvents = R.map((eventName) => Rx_1.Observable.fromEvent(this.ee, eventName), eventNames); | ||
return Rx_1.Observable.merge(...fromEvents) | ||
.mergeMap((normalized) => this.parser.parse(normalized)) | ||
.mergeMap((parsed) => this.parser.validate(parsed)) | ||
.mergeMap((validated) => { | ||
if (!validated) { | ||
return Rx_1.Observable.empty(); | ||
} | ||
return Promise.resolve(validated); | ||
}); | ||
} | ||
send(data) { | ||
this.logger.debug("sending", { message: data }); | ||
return broid_schemas_1.default(data, "send") | ||
.then(() => { | ||
if (data.object.type !== "Note") { | ||
return Promise.reject(new Error("Only Note is supported.")); | ||
} | ||
return Promise.resolve(data) | ||
.then((result) => { | ||
const roomID = R.path(["to", "id"], result); | ||
return this.channels() | ||
.filter((room) => room.id === roomID) | ||
.then((rooms) => { | ||
if (R.length(rooms) === 0) { | ||
throw new Error(`${roomID} not found.`); | ||
} | ||
return this.joinRoom(rooms[0]) | ||
.then((room) => [result, room]); | ||
}); | ||
}) | ||
.spread((result, room) => { | ||
const content = R.path(["object", "content"], result); | ||
const contentID = R.path(["object", "id"], result); | ||
if (contentID) { | ||
return this.session.client.put(`${room.path}/${room.id}/chatMessages/${contentID}`, { body: { text: content } }); | ||
} | ||
return room.send(content); | ||
}) | ||
.then((response) => ({ type: "sent", serviceID: this.serviceId(), id: response.id })); | ||
}); | ||
} | ||
joinRoom(room) { | ||
return new Promise((resolve, reject) => { | ||
if (room.uri) { | ||
return this.session.rooms.join(room.uri) | ||
.then(resolve) | ||
.catch(reject); | ||
} | ||
else if (room.url) { | ||
return this.session.rooms.join(room.url.replace(/^\/|\/$/g, "")) | ||
.then(resolve) | ||
.catch(reject); | ||
} | ||
return reject(new Error(`Cannot join room ${room.id}`)); | ||
}); | ||
} | ||
} | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.default = Adapter; |
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,3 @@ | ||
"use strict"; | ||
const adapter_1 = require("./adapter"); | ||
module.exports = adapter_1.default; |
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 @@ | ||
"use strict"; |
Oops, something went wrong.