Eslint: airbnb configuration
This commit is contained in:
parent
7c047f8231
commit
9981a25367
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"extends": "airbnb",
|
||||||
|
"rules": {
|
||||||
|
"func-names": ["error", "never"]
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,8 @@
|
||||||
import { createStore } from 'redux';
|
import { createStore } from 'redux';
|
||||||
import { startPeripheral } from 'redux-bluetooth/build/peripheral';
|
import startPeripheral from 'redux-bluetooth/build/peripheral';
|
||||||
|
|
||||||
import reducer from './reducer';
|
import reducer from './reducer';
|
||||||
|
|
||||||
let store = createStore(reducer);
|
const store = createStore(reducer);
|
||||||
|
|
||||||
startPeripheral('Counter', store);
|
startPeripheral('Counter', store);
|
|
@ -1,13 +1,13 @@
|
||||||
export default function counter(state = 0, { type }) {
|
export default function counter(state = 0, { type }) {
|
||||||
console.log('Counter: ---------------------------');
|
console.log('Counter: ---------------------------');
|
||||||
console.log(type)
|
console.log(type);
|
||||||
console.log(state)
|
console.log(state);
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'INCREMENT':
|
case 'INCREMENT':
|
||||||
return state + 1
|
return state + 1;
|
||||||
case 'DECREMENT':
|
case 'DECREMENT':
|
||||||
return state - 1
|
return state - 1;
|
||||||
default:
|
default:
|
||||||
return state
|
return state;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -10,38 +10,38 @@ export default class App extends PureComponent {
|
||||||
this.handlerConnect = this.handlerConnect.bind(this);
|
this.handlerConnect = this.handlerConnect.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
handlerConnect(){
|
handlerConnect() {
|
||||||
const { onConnect } = this.props;
|
const { onConnect } = this.props;
|
||||||
onConnect('Counter');
|
onConnect('Counter');
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const { store, status, onIncrement, onDecrement } = this.props;
|
||||||
store, status,
|
|
||||||
onIncrement, onDecrement
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="app">
|
<div className="app">
|
||||||
|
{status === 'CONNECTED' &&
|
||||||
{ (status === 'CONNECTED') &&
|
<div className="app-counter">
|
||||||
<div className="app-counter">{store}</div>
|
{store}
|
||||||
}
|
</div>}
|
||||||
<div className="app-actions">
|
<div className="app-actions">
|
||||||
{ (status !== 'CONNECTED') &&
|
{status !== 'CONNECTED' &&
|
||||||
<button className="app-actions__buton" onClick={this.handlerConnect}>Connect</button>
|
<button className="app-actions__buton" onClick={this.handlerConnect}>
|
||||||
}
|
Connect
|
||||||
{ (status === 'CONNECTED') &&
|
</button>}
|
||||||
<button className="app-actions__buton" onClick={onIncrement}>+</button>
|
{status === 'CONNECTED' &&
|
||||||
}
|
<button className="app-actions__buton" onClick={onIncrement}>
|
||||||
{ (status === 'CONNECTED') &&
|
+
|
||||||
<button className="app-actions__buton" onClick={onDecrement}>-</button>
|
</button>}
|
||||||
}
|
{status === 'CONNECTED' &&
|
||||||
|
<button className="app-actions__buton" onClick={onDecrement}>
|
||||||
|
-
|
||||||
|
</button>}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
App.propTypes = {
|
App.propTypes = {
|
||||||
store: PropTypes.number,
|
store: PropTypes.number,
|
||||||
|
@ -52,6 +52,8 @@ App.propTypes = {
|
||||||
};
|
};
|
||||||
|
|
||||||
App.defaultProps = {
|
App.defaultProps = {
|
||||||
|
store: 0,
|
||||||
|
status: '',
|
||||||
onConnect: () => true,
|
onConnect: () => true,
|
||||||
onIncrement: () => true,
|
onIncrement: () => true,
|
||||||
onDecrement: () => true,
|
onDecrement: () => true,
|
|
@ -5,9 +5,7 @@ import { increment, decrement } from '../actions';
|
||||||
|
|
||||||
import Component from './component';
|
import Component from './component';
|
||||||
|
|
||||||
const mapState = (state) => {
|
const mapState = state => state;
|
||||||
return state;
|
|
||||||
}
|
|
||||||
|
|
||||||
const mapAction = {
|
const mapAction = {
|
||||||
onConnect: actions.connectStore,
|
onConnect: actions.connectStore,
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
/* global document */
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { render } from 'react-dom';
|
import { render } from 'react-dom';
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
|
@ -11,11 +12,12 @@ import App from './app';
|
||||||
|
|
||||||
const ACTIONS = Object.keys(TYPES);
|
const ACTIONS = Object.keys(TYPES);
|
||||||
|
|
||||||
|
/* eslint-disable react/jsx-filename-extension */
|
||||||
const store = createSyncStore(ACTIONS);
|
const store = createSyncStore(ACTIONS);
|
||||||
render(
|
render(
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
<App />
|
<App />
|
||||||
</Provider>,
|
</Provider>,
|
||||||
document.getElementById('root')
|
document.getElementById('root'),
|
||||||
);
|
);
|
||||||
|
/* eslint-enable */
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
"main": "build/index.js",
|
"main": "build/index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "watch 'npm run build' src",
|
"dev": "watch 'npm run build' src",
|
||||||
|
"eslint": "eslint src",
|
||||||
|
"prebuild": "npm run eslint",
|
||||||
"build": "babel src -d build",
|
"build": "babel src -d build",
|
||||||
"test": "jest",
|
"test": "jest",
|
||||||
"test:watch": "npm test -- --watch",
|
"test:watch": "npm test -- --watch",
|
||||||
|
@ -39,12 +41,19 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"babel-cli": "^6.24.1",
|
"babel-cli": "^6.24.1",
|
||||||
"babel-preset-latest": "^6.24.1",
|
"babel-preset-latest": "^6.24.1",
|
||||||
|
"eslint": "^3.19.0",
|
||||||
|
"eslint-config-airbnb": "^15.0.2",
|
||||||
|
"eslint-plugin-import": "^2.7.0",
|
||||||
|
"eslint-plugin-jsx-a11y": "^5.1.1",
|
||||||
|
"eslint-plugin-react": "^7.1.0",
|
||||||
"jest": "^20.0.4",
|
"jest": "^20.0.4",
|
||||||
"np": "^2.16.0",
|
"np": "^2.16.0",
|
||||||
"watch": "^1.0.2"
|
"watch": "^1.0.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bleno": "^0.4.2",
|
"bleno": "^0.4.2",
|
||||||
|
"redux": "^3.7.1",
|
||||||
|
"redux-thunk": "^2.2.0",
|
||||||
"text-encoding": "^0.6.4"
|
"text-encoding": "^0.6.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
const CONFIG = {
|
const CONFIG = {
|
||||||
SERVICE_UUID: '13333333-3333-3333-3333-333333333337',
|
SERVICE_UUID: '13333333-3333-3333-3333-333333333337',
|
||||||
CHARACTERISTIC_UUID: '13333333-3333-3333-3333-333333330001'
|
CHARACTERISTIC_UUID: '13333333-3333-3333-3333-333333330001',
|
||||||
};
|
};
|
||||||
|
|
||||||
export const CENTRAL_CONFIG = CONFIG;
|
export const CENTRAL_CONFIG = CONFIG;
|
||||||
export const BLENO_CONFIG = {
|
export const BLENO_CONFIG = {
|
||||||
SERVICE_UUID: CONFIG.SERVICE_UUID.replace(/-/g, ''),
|
SERVICE_UUID: CONFIG.SERVICE_UUID.replace(/-/g, ''),
|
||||||
CHARACTERISTIC_UUID: CONFIG.CHARACTERISTIC_UUID.replace(/-/g, ''),
|
CHARACTERISTIC_UUID: CONFIG.CHARACTERISTIC_UUID.replace(/-/g, ''),
|
||||||
DESCRIPTOR_UUID: '2901'
|
DESCRIPTOR_UUID: '2901',
|
||||||
};
|
};
|
|
@ -1,17 +1,17 @@
|
||||||
export default function Encoder({ TextEncoder, TextDecoder}) {
|
export default function Encoder({ TextEncoder, TextDecoder }) {
|
||||||
const encoder = new TextEncoder('utf-8');
|
const encoder = new TextEncoder('utf-8');
|
||||||
const decoder = new TextDecoder('utf-8');
|
const decoder = new TextDecoder('utf-8');
|
||||||
|
|
||||||
const encode = (json) => {
|
const encode = (json) => {
|
||||||
const string = JSON.stringify(json);
|
const string = JSON.stringify(json);
|
||||||
return encoder.encode(string);
|
return encoder.encode(string);
|
||||||
}
|
};
|
||||||
|
|
||||||
const decode = (data) => {
|
const decode = (data) => {
|
||||||
const string = decoder.decode(data);
|
const string = decoder.decode(data);
|
||||||
const json = JSON.parse(string);
|
const json = JSON.parse(string);
|
||||||
return typeof json === 'string' ? JSON.parse(json) : json;
|
return typeof json === 'string' ? JSON.parse(json) : json;
|
||||||
}
|
};
|
||||||
|
|
||||||
return { encode, decode };
|
return { encode, decode };
|
||||||
}
|
}
|
|
@ -1,8 +1,9 @@
|
||||||
|
/* global test, expect */
|
||||||
import TextEncoding from 'text-encoding';
|
import TextEncoding from 'text-encoding';
|
||||||
|
|
||||||
import Encoder from '.';
|
import Encoder from '.';
|
||||||
|
|
||||||
const { encode , decode } = new Encoder(TextEncoding);
|
const { encode, decode } = new Encoder(TextEncoding);
|
||||||
|
|
||||||
test('encode / decode', () => {
|
test('encode / decode', () => {
|
||||||
const data = encode({ type: 'TEST', payload: 'PAYLOAD' });
|
const data = encode({ type: 'TEST', payload: 'PAYLOAD' });
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import * as peripheral from './peripheral';
|
import peripheral from './peripheral';
|
||||||
import * as webapp from './webapp';
|
import * as webapp from './webapp';
|
||||||
|
|
||||||
export default { peripheral, webapp };
|
export default { peripheral, webapp };
|
||||||
|
|
|
@ -1,15 +1,9 @@
|
||||||
export default function Characteristic(
|
export default function Characteristic(uuid, Parent, util, descriptor, { encode, decode }) {
|
||||||
uuid,
|
|
||||||
Parent,
|
|
||||||
util,
|
|
||||||
descriptor,
|
|
||||||
{ encode, decode } ) {
|
|
||||||
|
|
||||||
function ReduxCharacteristic() {
|
function ReduxCharacteristic() {
|
||||||
Parent.call(this, {
|
Parent.call(this, {
|
||||||
uuid,
|
uuid,
|
||||||
properties: ['read', 'write', 'notify'],
|
properties: ['read', 'write', 'notify'],
|
||||||
descriptors: [ descriptor ]
|
descriptors: [descriptor],
|
||||||
});
|
});
|
||||||
|
|
||||||
this.store = null;
|
this.store = null;
|
||||||
|
@ -17,51 +11,52 @@ export default function Characteristic(
|
||||||
|
|
||||||
util.inherits(ReduxCharacteristic, Parent);
|
util.inherits(ReduxCharacteristic, Parent);
|
||||||
|
|
||||||
ReduxCharacteristic.prototype.connect = function(store) {
|
ReduxCharacteristic.prototype.connect = function (store) {
|
||||||
this.store = store;
|
this.store = store;
|
||||||
this.store.subscribe(() => {
|
this.store.subscribe(() => {
|
||||||
if ( this.updateValueCallback && this.store ) {
|
if (this.updateValueCallback && this.store) {
|
||||||
const state = this.store.getState();
|
const state = this.store.getState();
|
||||||
this.updateValueCallback(encode(state));
|
this.updateValueCallback(encode(state));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
ReduxCharacteristic.prototype.disconnect = function() {
|
ReduxCharacteristic.prototype.disconnect = function () {
|
||||||
this.store = null;
|
this.store = null;
|
||||||
}
|
};
|
||||||
|
|
||||||
ReduxCharacteristic.prototype.onWriteRequest = function(data, offset, withoutResponse, callback) {
|
ReduxCharacteristic.prototype.onWriteRequest =
|
||||||
|
function (data, offset, withoutResponse, callback) {
|
||||||
if (offset) {
|
if (offset) {
|
||||||
callback(this.RESULT_ATTR_NOT_LONG);
|
callback(this.RESULT_ATTR_NOT_LONG);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.store && this.store.dispatch(decode(data));
|
if (this.store) this.store.dispatch(decode(data));
|
||||||
|
|
||||||
callback(this.RESULT_SUCCESS);
|
callback(this.RESULT_SUCCESS);
|
||||||
};
|
};
|
||||||
|
|
||||||
ReduxCharacteristic.prototype.onReadRequest = function(offset, callback) {
|
ReduxCharacteristic.prototype.onReadRequest = function (offset, callback) {
|
||||||
if (offset) {
|
if (offset) {
|
||||||
callback(this.RESULT_ATTR_NOT_LONG, null);
|
callback(this.RESULT_ATTR_NOT_LONG, null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !this.store ) {
|
if (!this.store) {
|
||||||
callback(this.RESULT_SUCCESS, null);
|
callback(this.RESULT_SUCCESS, null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
callback(this.RESULT_SUCCESS, encode(this.store.getState()));
|
callback(this.RESULT_SUCCESS, encode(this.store.getState()));
|
||||||
};
|
};
|
||||||
|
|
||||||
ReduxCharacteristic.prototype.onSubscribe = function(maxValueSize, updateValueCallback) {
|
ReduxCharacteristic.prototype.onSubscribe = function (maxValueSize, updateValueCallback) {
|
||||||
this.updateValueCallback = updateValueCallback;
|
this.updateValueCallback = updateValueCallback;
|
||||||
}
|
};
|
||||||
|
|
||||||
ReduxCharacteristic.prototype.onUnsubscribe = function() {
|
ReduxCharacteristic.prototype.onUnsubscribe = function () {
|
||||||
this.updateValueCallback = null;
|
this.updateValueCallback = null;
|
||||||
}
|
};
|
||||||
|
|
||||||
return new ReduxCharacteristic();
|
return new ReduxCharacteristic();
|
||||||
}
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
import util from 'util';
|
import util from 'util';
|
||||||
import bleno from 'bleno';
|
import BLENO from 'bleno';
|
||||||
import TextEncoding from 'text-encoding';
|
import TextEncoding from 'text-encoding';
|
||||||
|
|
||||||
import { BLENO_CONFIG } from '../../common/config';
|
import { BLENO_CONFIG } from '../../common/config';
|
||||||
|
@ -7,36 +7,26 @@ import Encoder from '../../common/encoder';
|
||||||
|
|
||||||
import Service from './service';
|
import Service from './service';
|
||||||
import Characteristic from './characteristic';
|
import Characteristic from './characteristic';
|
||||||
import Descriptor from './Descriptor';
|
import Descriptor from './descriptor';
|
||||||
|
|
||||||
export function Bleno(
|
export function Bleno(bleno, encoder, { SERVICE_UUID, CHARACTERISTIC_UUID, DESCRIPTOR_UUID }) {
|
||||||
bleno,
|
const descriptor = Descriptor(DESCRIPTOR_UUID, bleno.Descriptor);
|
||||||
encoder,
|
|
||||||
{ SERVICE_UUID, CHARACTERISTIC_UUID, DESCRIPTOR_UUID }) {
|
|
||||||
|
|
||||||
const descriptor = Descriptor(
|
|
||||||
DESCRIPTOR_UUID,
|
|
||||||
bleno.Descriptor
|
|
||||||
);
|
|
||||||
|
|
||||||
const characteristic = Characteristic(
|
const characteristic = Characteristic(
|
||||||
CHARACTERISTIC_UUID,
|
CHARACTERISTIC_UUID,
|
||||||
bleno.Characteristic,
|
bleno.Characteristic,
|
||||||
util,
|
util,
|
||||||
descriptor,
|
descriptor,
|
||||||
encoder);
|
encoder,
|
||||||
|
);
|
||||||
|
|
||||||
const service = Service(
|
const service = Service(SERVICE_UUID, bleno.PrimaryService, util, characteristic);
|
||||||
SERVICE_UUID,
|
|
||||||
bleno.PrimaryService,
|
|
||||||
util,
|
|
||||||
characteristic);
|
|
||||||
|
|
||||||
const start = (name, store) => {
|
const start = (name, store) => {
|
||||||
bleno.on('stateChange', function(state) {
|
bleno.on('stateChange', (state) => {
|
||||||
if (state === 'poweredOn') {
|
if (state === 'poweredOn') {
|
||||||
bleno.startAdvertising(name, [SERVICE_UUID], function(err) {
|
bleno.startAdvertising(name, [SERVICE_UUID], (err) => {
|
||||||
err && console.log('startAdvertising.err: ', err);
|
if (err) console.log('startAdvertising.err: ', err);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
bleno.stopAdvertising();
|
bleno.stopAdvertising();
|
||||||
|
@ -44,19 +34,15 @@ export function Bleno(
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
bleno.on('advertisingStart', function(err) {
|
bleno.on('advertisingStart', (err) => {
|
||||||
if (!err) {
|
if (!err) {
|
||||||
bleno.setServices([ service ]);
|
bleno.setServices([service]);
|
||||||
characteristic.connect(store);
|
characteristic.connect(store);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
return { start };
|
return { start };
|
||||||
}
|
}
|
||||||
|
|
||||||
export default new Bleno(
|
export default new Bleno(BLENO, Encoder(TextEncoding), BLENO_CONFIG);
|
||||||
bleno,
|
|
||||||
Encoder(TextEncoding),
|
|
||||||
BLENO_CONFIG
|
|
||||||
);
|
|
||||||
|
|
|
@ -1,9 +1,4 @@
|
||||||
export default function Service(
|
export default function Service(uuid, Parent, util, characteristic) {
|
||||||
uuid,
|
|
||||||
Parent,
|
|
||||||
util,
|
|
||||||
characteristic) {
|
|
||||||
|
|
||||||
function ReduxService() {
|
function ReduxService() {
|
||||||
Parent.call(this, {
|
Parent.call(this, {
|
||||||
uuid,
|
uuid,
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
import bleno from './bleno';
|
import bleno from './bleno';
|
||||||
|
|
||||||
export const startPeripheral = (name, store) => bleno.start(name, store);
|
export default (name, store) => bleno.start(name, store);
|
||||||
|
|
|
@ -1,31 +1,26 @@
|
||||||
export default function Actions(central, TYPES) {
|
export default function Actions(central, TYPES) {
|
||||||
|
const syncState = state => ({
|
||||||
const syncState = (state) => ({
|
|
||||||
type: TYPES.BLUETOOTH_SYNC,
|
type: TYPES.BLUETOOTH_SYNC,
|
||||||
payload: state
|
payload: state,
|
||||||
});
|
});
|
||||||
|
|
||||||
const connectStore = (name) => dispatch => {
|
const syncStore = () => dispatch => central.read().then(state => dispatch(syncState(state)));
|
||||||
|
|
||||||
|
const connectStore = name => (dispatch) => {
|
||||||
dispatch({ type: TYPES.BLUETOOTH_CONNECTING });
|
dispatch({ type: TYPES.BLUETOOTH_CONNECTING });
|
||||||
return central.connect(name)
|
return central
|
||||||
.then(() => central.handler((state) => dispatch(syncState(state))))
|
.connect(name)
|
||||||
|
.then(() => central.handler(state => dispatch(syncState(state))))
|
||||||
.then(() => dispatch({ type: TYPES.BLUETOOTH_CONNECTED }))
|
.then(() => dispatch({ type: TYPES.BLUETOOTH_CONNECTED }))
|
||||||
.then(() => dispatch(syncStore()));
|
.then(() => dispatch(syncStore()));
|
||||||
};
|
};
|
||||||
|
|
||||||
const syncStore = () => dispatch => {
|
const sendAction = action => () => central.write(action);
|
||||||
return central.read()
|
|
||||||
.then(state => dispatch(syncState(state)));
|
|
||||||
};
|
|
||||||
|
|
||||||
const sendAction = (action) => _ => {
|
|
||||||
return central.write(action);
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
connectStore,
|
connectStore,
|
||||||
syncStore,
|
syncStore,
|
||||||
syncState,
|
syncState,
|
||||||
sendAction,
|
sendAction,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
/* global jest, beforeEach, afterEach, test, expect */
|
||||||
import * as TYPES from './types';
|
import * as TYPES from './types';
|
||||||
import Actions from './actions';
|
import Actions from './actions';
|
||||||
|
|
||||||
|
@ -25,7 +26,7 @@ test('syncState', () => {
|
||||||
|
|
||||||
expect(action).toEqual({
|
expect(action).toEqual({
|
||||||
type: TYPES.BLUETOOTH_SYNC,
|
type: TYPES.BLUETOOTH_SYNC,
|
||||||
payload: 'mockState'
|
payload: 'mockState',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -33,7 +34,7 @@ test('connectStore', () => {
|
||||||
const { connectStore } = Actions(central, TYPES);
|
const { connectStore } = Actions(central, TYPES);
|
||||||
expect.assertions(6);
|
expect.assertions(6);
|
||||||
|
|
||||||
const promise = connectStore('mockName')(dispatch).then(_ => {
|
const promise = connectStore('mockName')(dispatch).then(() => {
|
||||||
expect(central.connect).toBeCalled();
|
expect(central.connect).toBeCalled();
|
||||||
expect(central.handler).toBeCalled();
|
expect(central.handler).toBeCalled();
|
||||||
|
|
||||||
|
@ -51,7 +52,7 @@ test('syncStore', () => {
|
||||||
const { syncStore } = Actions(central, TYPES);
|
const { syncStore } = Actions(central, TYPES);
|
||||||
expect.assertions(3);
|
expect.assertions(3);
|
||||||
|
|
||||||
const promise = syncStore()(dispatch).then(_ => {
|
const promise = syncStore()(dispatch).then(() => {
|
||||||
expect(central.read).toBeCalled();
|
expect(central.read).toBeCalled();
|
||||||
expect(dispatch).toBeCalledWith({ type: TYPES.BLUETOOTH_SYNC, payload: 'mockState' });
|
expect(dispatch).toBeCalledWith({ type: TYPES.BLUETOOTH_SYNC, payload: 'mockState' });
|
||||||
|
|
||||||
|
@ -65,7 +66,7 @@ test('sendAction', () => {
|
||||||
const { sendAction } = Actions(central, TYPES);
|
const { sendAction } = Actions(central, TYPES);
|
||||||
expect.assertions(2);
|
expect.assertions(2);
|
||||||
|
|
||||||
const promise = sendAction('mockAction')(dispatch).then(_ => {
|
const promise = sendAction('mockAction')(dispatch).then(() => {
|
||||||
expect(central.write).toBeCalledWith('mockAction');
|
expect(central.write).toBeCalledWith('mockAction');
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -1,69 +1,59 @@
|
||||||
import { CENTRAL_CONFIG } from '../../common/config';
|
import { CENTRAL_CONFIG } from '../../common/config';
|
||||||
import Encoder from '../../common/encoder';
|
import Encoder from '../../common/encoder';
|
||||||
|
|
||||||
export function Central(
|
export function Central(bluetooth, { encode, decode }, { SERVICE_UUID, CHARACTERISTIC_UUID }) {
|
||||||
bluetooth,
|
|
||||||
{ encode, decode },
|
|
||||||
{ SERVICE_UUID, CHARACTERISTIC_UUID }) {
|
|
||||||
|
|
||||||
const state = {
|
const state = {
|
||||||
server: null,
|
server: null,
|
||||||
characteristic: null,
|
characteristic: null,
|
||||||
}
|
|
||||||
|
|
||||||
const connect = (name) => {
|
|
||||||
return bluetooth.requestDevice({
|
|
||||||
filters: [{ services: [ SERVICE_UUID ], name: name }]
|
|
||||||
})
|
|
||||||
.then((device) => device.gatt.connect())
|
|
||||||
.then((server) => {
|
|
||||||
state.server = server;
|
|
||||||
return server.getPrimaryService(SERVICE_UUID)
|
|
||||||
})
|
|
||||||
.then((service) => service.getCharacteristic(CHARACTERISTIC_UUID))
|
|
||||||
.then((characteristic) => {
|
|
||||||
state.characteristic = characteristic;
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handler = ( callback ) => {
|
const connect = name => bluetooth
|
||||||
return state.characteristic.startNotifications()
|
.requestDevice({
|
||||||
.then(() => {
|
filters: [{ services: [SERVICE_UUID], name }],
|
||||||
state.characteristic.addEventListener('characteristicvaluechanged', (event) => {
|
})
|
||||||
callback(decode(event.target.value));
|
.then(device => device.gatt.connect())
|
||||||
|
.then((server) => {
|
||||||
|
state.server = server;
|
||||||
|
return server.getPrimaryService(SERVICE_UUID);
|
||||||
|
})
|
||||||
|
.then(service => service.getCharacteristic(CHARACTERISTIC_UUID))
|
||||||
|
.then((characteristic) => {
|
||||||
|
state.characteristic = characteristic;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const handler = callback => state.characteristic.startNotifications().then(() => {
|
||||||
|
state.characteristic.addEventListener('characteristicvaluechanged', (event) => {
|
||||||
|
callback(decode(event.target.value));
|
||||||
});
|
});
|
||||||
}
|
});
|
||||||
|
|
||||||
const read = () => {
|
const read = () => {
|
||||||
if ( state.server && state.server.connected && state.characteristic ) {
|
if (state.server && state.server.connected && state.characteristic) {
|
||||||
return state.characteristic.readValue().then(data => {
|
return state.characteristic.readValue().then(data => decode(data));
|
||||||
return decode(data);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
return Promise.reject(new Error('Bluetooth: Not Connected'));
|
return Promise.reject(new Error('Bluetooth: Not Connected'));
|
||||||
}
|
};
|
||||||
|
|
||||||
const write = (action) => {
|
const write = (action) => {
|
||||||
if ( state.server && state.server.connected && state.characteristic ) {
|
if (!state.server || !state.server.connected || !state.characteristic) return null;
|
||||||
const stringify = JSON.stringify(action);
|
const stringify = JSON.stringify(action);
|
||||||
const serialized = encode(stringify);
|
const serialized = encode(stringify);
|
||||||
|
|
||||||
return state.characteristic.writeValue(serialized);
|
return state.characteristic.writeValue(serialized);
|
||||||
}
|
};
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
connected: state.server && state.server.connected,
|
connected: state.server && state.server.connected,
|
||||||
connect,
|
connect,
|
||||||
handler,
|
handler,
|
||||||
read,
|
read,
|
||||||
write
|
write,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* global navigator TextEncoder TextDecoder */
|
||||||
export default new Central(
|
export default new Central(
|
||||||
navigator.bluetooth,
|
navigator.bluetooth,
|
||||||
Encoder({ TextEncoder, TextDecoder }),
|
Encoder({ TextEncoder, TextDecoder }),
|
||||||
CENTRAL_CONFIG
|
CENTRAL_CONFIG,
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
import actions from '../actions';
|
import ACTIONS from '../actions';
|
||||||
const { sendAction } = actions;
|
|
||||||
|
|
||||||
export default (actions = []) => store => next => action => {
|
const { sendAction } = ACTIONS;
|
||||||
|
|
||||||
|
export default (actions = []) => store => next => (action) => {
|
||||||
const { type } = action;
|
const { type } = action;
|
||||||
actions.includes(type) && store.dispatch(sendAction(action));
|
if (actions.includes(type)) store.dispatch(sendAction(action));
|
||||||
return next(action);
|
return next(action);
|
||||||
}
|
};
|
||||||
|
|
|
@ -2,7 +2,7 @@ import * as TYPES from '../actions/types';
|
||||||
import * as STATUS from '../central/status';
|
import * as STATUS from '../central/status';
|
||||||
|
|
||||||
const initial = {
|
const initial = {
|
||||||
status: STATUS.INIT
|
status: STATUS.INIT,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default (autosync = true) => (state = initial, { type, payload }) => {
|
export default (autosync = true) => (state = initial, { type, payload }) => {
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
/* global window */
|
||||||
import { createStore, applyMiddleware, compose } from 'redux';
|
import { createStore, applyMiddleware, compose } from 'redux';
|
||||||
import thunk from 'redux-thunk';
|
import thunk from 'redux-thunk';
|
||||||
|
|
||||||
|
@ -5,20 +6,14 @@ import middleware from '../middleware';
|
||||||
import reducers from '../reducers';
|
import reducers from '../reducers';
|
||||||
|
|
||||||
export default (actions) => {
|
export default (actions) => {
|
||||||
const middlewares = [
|
const middlewares = [middleware(actions), thunk];
|
||||||
middleware(actions),
|
const enhancers = [applyMiddleware(...middlewares)];
|
||||||
thunk
|
|
||||||
];
|
|
||||||
const enhancers = [
|
|
||||||
applyMiddleware(...middlewares),
|
|
||||||
];
|
|
||||||
|
|
||||||
|
/* eslint-disable no-underscore-dangle */
|
||||||
if (typeof window === 'object' && window.__REDUX_DEVTOOLS_EXTENSION__) {
|
if (typeof window === 'object' && window.__REDUX_DEVTOOLS_EXTENSION__) {
|
||||||
enhancers.push(window.__REDUX_DEVTOOLS_EXTENSION__());
|
enhancers.push(window.__REDUX_DEVTOOLS_EXTENSION__());
|
||||||
}
|
}
|
||||||
|
/* eslint-enable */
|
||||||
|
|
||||||
return createStore(
|
return createStore(reducers(), compose(...enhancers));
|
||||||
reducers(),
|
};
|
||||||
compose(...enhancers),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue