Skip to content

Commit

Permalink
#3 Refactor: resolve review comments
Browse files Browse the repository at this point in the history
  • Loading branch information
IvanBlacky committed Feb 8, 2019
1 parent a392469 commit e9cf1f8
Show file tree
Hide file tree
Showing 9 changed files with 113 additions and 68 deletions.
7 changes: 4 additions & 3 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
GLS_CONNECTOR_HOST=127.0.0.1
GLS_CONNECTOR_HOST=0.0.0.0
GLS_CONNECTOR_PORT=3000
GLS_METRICS_HOST=
GLS_METRICS_PORT=
GLS_MONGO_CONNECT=mongodb://localhost:27017/admin
GLS_MONGO_CONNECT=mongodb://bandwidth_mongo:27017/admin
CMN_CYBERWAY_HTTP_URL=
CMN_PROVIDER_PUBLIC_KEY=
CMN_PROVIDER_WIF=
CMN_PROVIDER_USERNAME=
GLS_CHANNEL_TTL=
CMN_REGISTRATION_CONNECT=
CMN_CHANNEL_TTL=
7 changes: 7 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
FROM node:10-alpine
WORKDIR /usr/src/app
COPY ./package*.json ./
COPY ./.npmrc ./
RUN npm install --only=production
COPY ./src/ ./src
CMD [ "node", "./src/index.js" ]
51 changes: 42 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,34 +1,67 @@
# Bandwidth service

**Bandwidth service** является сервисом для предоставления необходимых мощностей пользователям [golos.io](https://golos.io) (например, для публикации постов).
**Bandwidth service** является сервисом для предоставления необходимых мощностей (бендвича) пользователям [golos.io](https://golos.io) (например, для публикации постов).
Сервис подписывает транзакции вместо пользователя, сохраняя его авторство.

### Основное

Микросервис реализует один метод:
Микросервис содержит 2 контроллера и 1 сервис, помимо служебных:

- 'bandwidth.provide': будет добавлено позже
#### Сервисы:

- `Storage`: сервис, который является, по сути, базой данных в оперативной памяти. Его задачей является хранение имен пользователей и идентификаторов каналов, а также самоочищаться раз в один час. Предоставляет публичные методы для добавления/удаления пользователей в базу, для проверки, есть ли пользователь в базе и для удаления канала соединения при его разрыве.

#### Контроллеры:

- `Whitelist`: контроллер, задачей которого является управление списком пользователей, которым разрешен доступ к запросу бендвича. Данный контроллер предоставляет два публичных метода класса: на бан пользователя и на проверку доступа по его имени и его идентификатору канала (`channelId`, `cid`). Когда запрашивается проверка доступа, сначала контроллер ищет пользователя в базе данных в памяти (storage service), и если он там не найден, то в базе данных монго, а если и там пользователь не найден, то контроллер делает запрос в сервис регистрации. Если пользователь найден в сервисе регистрации, то он добавляется и в монго и в базу данных в памяти, если нет, то доступ запрещается. Если пользователь забанен (что выясняется на этапе запроса к монго), то доступ запрещается. Когда запрашивается бан пользователя, то в базе данных пользователю присваивается флаг "забанен" и он удаляется из базы данных в памяти.

- `Bandwidth Provider`: контроллер, который предоставляет один публичный метод: предоставления бендвича. Этот метод принимает транзакцию и проверяет, есть ли в ней запрос на предоставление бендвича и совпадает ли имя пользователя, который должен предоставить бендвич с пользователем, от имени которого запущен микросервис, а также, разрешено ли пользователю запрашивать бендвич. Если транзакцию не требуется подписывать, то она передается в блокчейн. Если требуется, и у пользователя есть право это запросить, то транзакция подписывается и передается в блокчейн.

Микросервис реализует 3 метода:

- 'bandwidth.provide': метод, который принимает транзакцию, для которой требуется предоставить бендвич, подписывает и отправляет ее в блокчейн. Метод возвращает ответ от блокчейна.
- 'bandwidth.banUser': метод, который принимает имя пользователя, которого требуется исключить пользователя из списка пользователей, которым разрешено получение бендвича (вайтлист). Возвращает статус исполнения запроса.
- 'bandwidth.notifyOffline': метод, который принимает имя пользователя, статус которого поменялся на "оффлайн", а также его `channelId` и исключает его из вайтлиста, который хранится в оперативной памяти (но не из базы данных).

##### API JSON-RPC

Будет добавлено позже
- `bandwidth.provide`: принимает параметры вида `{transaction, chainId}`, возвращает ответ от блокчейна либо ошибку
- `bandwidth.banUser`: принимает параметры вида `{user, channelId}`, возвращает статус либо ошибку
- `bandwidth.notifyOffline`: принимает параметры вида `{user, channelId}`, возвращает статус либо ошибку

### Переменные окружения

Возможные переменные окружения `ENV`:

- `GLS_CONNECTOR_HOST` _(обязательно)_ - адрес, который будет использован для входящих подключений связи микросервисов.
- `GLS_CONNECTOR_HOST` _(обязательно)_ - адрес, который будет использован для входящих подключений связи микросервисов.
Дефолтное значение при запуске без докера - `127.0.0.1`

- `GLS_CONNECTOR_PORT` _(обязательно)_ - адрес порта, который будет использован для входящих подключений связи микросервисов.
- `GLS_CONNECTOR_PORT` _(обязательно)_ - адрес порта, который будет использован для входящих подключений связи микросервисов.
Дефолтное значение при запуске без докера - `3000`, пересекается с `GLS_FRONTEND_GATE_PORT`

- `GLS_METRICS_HOST` _(обязательно)_ - адрес хоста для метрик StatsD.
- `GLS_METRICS_HOST` _(обязательно)_ - адрес хоста для метрик StatsD.
Дефолтное значение при запуске без докера - `127.0.0.1`

- `GLS_METRICS_PORT` _(обязательно)_ - адрес порта для метрик StatsD.
Дефолтное значение при запуске без докера - `8125`
- `GLS_METRICS_PORT` _(обязательно)_ - адрес порта для метрик StatsD. Дефолтное значение при запуске без докера - `8125`

- `GLS_MONGO_CONNECT` _(обязательно)_ - ссылка на подключение к MongoDB

- `CMN_CYBERWAY_HTTP_URL` _(обязательно)_ - ссылка на подключение к блокчейну Cyberway

- `CMN_PROVIDER_PUBLIC_KEY` _(обязательно)_ - публичный ключ провайдера бендвича

- `CMN_PROVIDER_WIF` _(обязательно)_ - приватный ключ провайдера бендвича

- `CMN_PROVIDER_USERNAME` _(обязательно)_ - имя пользователя провайдера бендвича

- `CMN_REGISTRATION_CONNECT` _(обязательно)_ - ссылка на подключение к сервису регистрации

- `CMN_CHANNEL_TTL` _(обязательно)_ - время жизни канала (время, которое будет хранится channelId в базе данных в памяти). **Важно:** _storage проверяет, не превышено ли это значение лишь раз в час, поэтому между тем, как данный лимит будет превышен, и тем, как канал будет фактически удален из памяти, может пройти существенное количество времени_

### Запуск

Для запуска достаточно вызвать команду `docker-compose up` в корне проекта, предварительно указав необходимые `ENV` переменные.

```
```
31 changes: 0 additions & 31 deletions docker-compose.yaml

This file was deleted.

33 changes: 33 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
version: '3.6'
services:
node:
container_name: bandwidth-provider-node
restart: always
build:
context: .
dockerfile: Dockerfile
networks:
- services-tier
ports:
- $GLS_CONNECTOR_HOST:$GLS_CONNECTOR_PORT:$GLS_CONNECTOR_PORT
env_file:
- .env
depends_on:
- mongo

mongo:
container_name: bandwidth_mongo
image: mongo
restart: always
volumes:
- badwidth_mongodb_vol:/data/db
ports:
- 127.0.0.1:27017:27017
networks:
- services-tier

networks:
services-tier:

volumes:
badwidth_mongodb_vol:
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
const { TextEncoder, TextDecoder } = require('text-encoding'); // node only; native TextEncoder/Decoder
const { TextEncoder, TextDecoder } = require('text-encoding');
const core = require('gls-core-service');
const fetch = require('node-fetch'); // node only; not needed in browsers
const fetch = require('node-fetch');
const { JsonRpc, Api } = require('cyberwayjs');
const JsSignatureProvider = require('cyberwayjs/dist/eosjs-jssig').default;
const BasicService = core.services.Basic;
const BasicController = core.controllers.Basic;
const env = require('../data/env');
const {
CMN_PROVIDER_WIF,
Expand All @@ -24,11 +24,11 @@ const api = new Api({
textEncoder: new TextEncoder(),
});

class BandwidthProvider extends BasicService {
class BandwidthProvider extends BasicController {
constructor({ whitelist }) {
super();

this.whitelist = whitelist;
this._whitelist = whitelist;
}

start() {
Expand Down Expand Up @@ -65,29 +65,27 @@ class BandwidthProvider extends BasicService {
auth: { user },
params: { transaction, chainId },
}) {
const isAllowed = await this.whitelist.isAllowed({ channelId, user });

if (!isAllowed) {
throw {
code: 1103,
message: 'This user is not allowed to require bandwidth',
};
}

const serializedTransactionBuffer = Uint8Array.from(transaction.serializedTransaction);
transaction.serializedTransaction = serializedTransactionBuffer;
transaction.serializedTransaction = Uint8Array.from(transaction.serializedTransaction);

const deserializedTransaction = await api.deserializeTransactionWithActions(
transaction.serializedTransaction
);

const shouldProvideBandwidth = deserializedTransaction.actions.find(action => {
return action.name === 'providebw' && action.data.provider === CMN_PROVIDER_USERNAME;
});

let transactionToSend = transaction;

if (shouldProvideBandwidth) {
const isAllowed = await this._whitelist.isAllowed({ channelId, user });

if (!isAllowed) {
throw {
code: 1103,
message: 'This user is not allowed to require bandwidth',
};
}

transactionToSend = await this._signTransaction({ transaction, chainId });
}

Expand Down
3 changes: 2 additions & 1 deletion src/data/env.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ module.exports = {
CMN_PROVIDER_WIF: env.CMN_PROVIDER_WIF,
CMN_PROVIDER_USERNAME: env.CMN_PROVIDER_USERNAME,
CMN_PROVIDER_PUBLIC_KEY: env.CMN_PROVIDER_PUBLIC_KEY,
GLS_CHANNEL_TTL: env.GLS_CHANNEL_TTL || 1000,
CMN_CHANNEL_TTL: env.CMN_CHANNEL_TTL || 1000,
CMN_CYBERWAY_HTTP_URL: env.CMN_CYBERWAY_HTTP_URL,
CMN_REGISTRATION_CONNECT: env.CMN_REGISTRATION_CONNECT,
};
13 changes: 8 additions & 5 deletions src/services/Connector.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
const core = require('gls-core-service');
const BasicConnector = core.services.Connector;
const BandwidthProvider = require('./BandwidthProvider');
const BandwidthProvider = require('../controllers/BandwidthProvider');
const StorageService = require('./StorageService');
const Whitelist = require('../controllers/Whitelist');
const env = require('../data/env');

class Connector extends BasicConnector {
constructor() {
super();
this._storageService = new StorageService();
this.addNested(this._storageService);
this._whitelistController = new Whitelist({
connector: this,
storage: this._storageService,
Expand All @@ -18,20 +20,21 @@ class Connector extends BasicConnector {
}

async start() {
const storage = this._storageService;
const provider = this._bandwidthProvider;
const whitelist = this._whitelistController;

await provider.start();
await storage.start();

await super.start({
serverRoutes: {
'bandwidth.provide': provider.provideBandwidth.bind(provider),
'bandwidth.banUser': whitelist.banUser.bind(whitelist),
'bandwidth.notifyOffline': whitelist.handleOffline.bind(whitelist),
},
requiredClients: {
registration: env.CMN_REGISTRATION_CONNECT,
},
});

await this.startNested();
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/services/StorageService.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const core = require('gls-core-service');
const BasicService = core.services.Basic;
const env = require('../data/env');
const { GLS_CHANNEL_TTL } = env;
const { CMN_CHANNEL_TTL } = env;

class Storage extends BasicService {
constructor() {
Expand All @@ -21,7 +21,7 @@ class Storage extends BasicService {
_cleanup() {
const now = Date.now();
for ([channelId, lastRequestDate] of this._timeoutMap) {
const shouldBeDeleted = now - lastRequestDate >= GLS_CHANNEL_TTL;
const shouldBeDeleted = now - lastRequestDate >= CMN_CHANNEL_TTL;

if (shouldBeDeleted) {
this._timeoutMap.delete(channelId);
Expand Down

0 comments on commit e9cf1f8

Please sign in to comment.