Skip to content

Commit

Permalink
implement and apply storage module in app (#39)
Browse files Browse the repository at this point in the history
  • Loading branch information
nionata committed Nov 22, 2021
1 parent f330049 commit d4e4e22
Show file tree
Hide file tree
Showing 14 changed files with 264 additions and 119 deletions.
23 changes: 18 additions & 5 deletions app/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"react-native-safe-area-context": "^3.3.2",
"react-native-screens": "^3.8.0",
"react-native-ui-lib": "^6.0.0",
"react-native-uuid": "^2.0.1",
"react-native-vector-icons": "^8.1.0",
"swears": "^0.1.6",
"ts-proto": "^1.87.0"
Expand Down
95 changes: 49 additions & 46 deletions app/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@ import { StyleSheet } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import Ionicons from 'react-native-vector-icons/Ionicons';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { Text, TouchableOpacity } from 'react-native-ui-lib';
import Modal from 'react-native-modalbox';

// Custom
import BluetoothManager from 'bluetooth/manager';
import { Message } from 'api/message';
import { Peer } from 'bluetooth';
import { AppProps, AppState } from 'index';
import { GRAPEVINE_MESSAGE } from 'Const';
import BluetoothManager from 'bluetooth/manager';
import { Storage } from 'storage';
import LocalStorgage from 'storage/local';
import { TEST_MESSAGES, TEST_PEERS } from 'data.test';
import { TESTING } from 'const';

// Screens
import HomeScreen from 'screens/home';
Expand All @@ -25,49 +25,58 @@ const Tab = createBottomTabNavigator();

class App extends React.Component<AppProps, AppState> {
private composeRef: React.RefObject<Modal>;

private storage: Storage;
private bluetoothManager: BluetoothManager;
private stateTicker: NodeJS.Timer | undefined;

constructor(props: AppProps) {
super(props);
this.composeRef = React.createRef();

this.state = {
messages: [],
manager: new BluetoothManager(
() => this.state.messages,
async () => {
const message = (await AsyncStorage.getItem(GRAPEVINE_MESSAGE)) || '';
return [
{
content: message,
},
];
},
(message: Message) => {
this.setState((state) => {
return {
...state,
messages: [...state.messages, message],
};
});
},
() => this.state.peers,
(id: string, peer: Peer) => {
this.setState((state) => {
return {
...state,
peers: {
...state.peers,
[id]: peer,
},
};
});
}
),
peers: {},
messages: TESTING ? TEST_MESSAGES : [],
peers: TESTING ? TEST_PEERS : {},
};
this.state.manager.start().then(() => {
this.composeRef = React.createRef();

this.storage = new LocalStorgage();
this.bluetoothManager = new BluetoothManager(this.storage);
this.stateTicker = setInterval(() => this.hydrateState(), 5 * 1000);
this.hydrateState();
this.bluetoothManager.start().then(() => {
console.log('Bluetooth manager started');
});
}

componentWillUnmount() {
this.bluetoothManager.stop().then(() => {
console.log('Bluetooth manager stopped');
});
if (this.stateTicker) {
clearInterval(this.stateTicker);
}
}

async hydrateState() {
try {
const messages = await this.storage.getMessages('received');
const peers = await this.storage.getPeers();
this.setState((state) => {
return {
...state,
messages: [...state.messages, ...messages],
peers: {
...state.peers,
...peers,
},
};
});
console.log('State hydrated');
} catch (err) {
console.error(err);
}
}

onClose() {
console.log('Modal just closed');
}
Expand All @@ -80,12 +89,6 @@ class App extends React.Component<AppProps, AppState> {
console.log('the open/close of the swipeToClose just changed', state);
}

componentWillUnmount() {
this.state.manager.stop().then(() => {
console.log('Bluetooth manager stopped');
});
}

render() {
return (
<NavigationContainer>
Expand Down
42 changes: 14 additions & 28 deletions app/src/bluetooth/central.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,18 @@ import {
} from 'bluetooth/const';
import { Messages } from 'api/message';
import { fromByteArray } from 'base64-js';
import {
GetPeers,
GetTransmittableMessages,
Peer,
SetPeer,
Task,
} from 'bluetooth';
import { Peer, Task } from 'bluetooth';
import { Storage } from 'storage';

export default class BluetoothCentral implements Task {
poweredOn: boolean;
private manager: BleManager;
private getPeers: GetPeers;
private setPeer: SetPeer;
private getTransmittableMessages: GetTransmittableMessages;
private storage: Storage;

constructor(
getPeers: GetPeers,
setPeer: SetPeer,
getTransmittableMessages: GetTransmittableMessages
) {
constructor(storage: Storage) {
this.poweredOn = false;
this.manager = new BleManager();
this.getPeers = getPeers;
this.setPeer = setPeer;
this.getTransmittableMessages = getTransmittableMessages;
this.storage = storage;
}

/**
Expand Down Expand Up @@ -87,7 +74,7 @@ export default class BluetoothCentral implements Task {
}

// Log a new encounter for an existing or new peer
const peers = this.getPeers();
const peers = await this.storage.getPeers();
let peer: Peer = peers[scannedDevice.id]
? peers[scannedDevice.id]
: {
Expand All @@ -103,10 +90,10 @@ export default class BluetoothCentral implements Task {
console.log(
`Discovered device '${peer.device.id}' (${peer.encounters} / ${peer.transmissions})`
);
this.setPeer(scannedDevice.id, peer);
await this.storage.setPeer(scannedDevice.id, peer);

// Encode the applicable messages
const messages = await this.getTransmittableMessages();
const messages = await this.storage.getMessages('authored');
console.log(`Transmitting messages '${messages}'`);
const messagesByteArr = Messages.encode(
Messages.fromJSON({
Expand All @@ -123,15 +110,14 @@ export default class BluetoothCentral implements Task {
console.log(
`Discovered services ${discoveredDevice.serviceUUIDs} on device ${discoveredDevice.id}`
);
const characterisc =
await discoveredDevice.writeCharacteristicWithResponseForService(
GRAPEVINE_SERVICE_UUID,
MESSAGE_CHARACTERISTIC_UUID,
fromByteArray(messagesByteArr)
);
await discoveredDevice.writeCharacteristicWithResponseForService(
GRAPEVINE_SERVICE_UUID,
MESSAGE_CHARACTERISTIC_UUID,
fromByteArray(messagesByteArr)
);
peer.transmissions++;
console.log(`Transmitted messages to device '${discoveredDevice.id}'`);
this.setPeer(scannedDevice.id, peer);
await this.storage.setPeer(scannedDevice.id, peer);
} catch (err) {
console.error(err);
}
Expand Down
1 change: 0 additions & 1 deletion app/src/bluetooth/const.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,3 @@ export const MESSAGE_CHARACTERISTIC_UUID: string =
'3fa13acd-e384-40fc-87a4-2c5fe5eec067';
export const ID_CHARACTERISTIC_UUID: string =
'22c180b9-5c6d-4511-8e44-973b4707113a';
export const GRAPEVINE_MESSAGE = '@grapevine_message';
7 changes: 0 additions & 7 deletions app/src/bluetooth/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
import { Message } from 'api/message';
import { Device } from 'react-native-ble-plx';

export type GetMessages = () => Message[];
export type GetTransmittableMessages = () => Promise<Message[]>;
export type SetMessage = (message: Message) => void;

export interface Peer {
device: Device;
encounters: number;
Expand All @@ -13,8 +8,6 @@ export interface Peer {
mtu: number;
}
export type Peers = { [key: string]: Peer };
export type GetPeers = () => Peers;
export type SetPeer = (id: string, peer: Peer) => void;

export interface Task {
poweredOn: boolean;
Expand Down
24 changes: 4 additions & 20 deletions app/src/bluetooth/manager.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,6 @@
import BluetoothCentral from 'bluetooth/central';
import BluetoothPeripheral from 'bluetooth/peripheral';
import {
GetMessages,
GetPeers,
GetTransmittableMessages,
SetMessage,
SetPeer,
} from 'bluetooth';
import { Storage } from 'storage';

export enum BluetoothMode {
Scan,
Expand All @@ -18,19 +12,9 @@ export default class BluetoothManager {
peripheral: BluetoothPeripheral;
tickler: NodeJS.Timer | undefined;

constructor(
getMessages: GetMessages,
getTransmittableMessages: GetTransmittableMessages,
setMessage: SetMessage,
getPeers: GetPeers,
setPeer: SetPeer
) {
this.central = new BluetoothCentral(
getPeers,
setPeer,
getTransmittableMessages
);
this.peripheral = new BluetoothPeripheral(getMessages, setMessage);
constructor(storage: Storage) {
this.central = new BluetoothCentral(storage);
this.peripheral = new BluetoothPeripheral(storage);
}

/**
Expand Down
22 changes: 12 additions & 10 deletions app/src/bluetooth/peripheral.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,24 @@ import {
GRAPEVINE_SERVICE_UUID,
MESSAGE_CHARACTERISTIC_UUID,
} from 'bluetooth/const';
import { Message, Messages } from 'api/message';
import { Messages } from 'api/message';
import { toByteArray, fromByteArray } from 'base64-js';
import { GetMessages, SetMessage, Task } from 'bluetooth';
import { Task } from 'bluetooth';
import { Storage } from 'storage';

export default class BluetoothPeripheral implements Task {
poweredOn: boolean;
private manager: Manager;
private storage: Storage;
private service: Service;

constructor(getMessages: GetMessages, setMessage: SetMessage) {
constructor(storage: Storage) {
this.poweredOn = false;
this.manager = new Manager();
this.storage = storage;
this.service = new Service({
uuid: GRAPEVINE_SERVICE_UUID,
characteristics: [this.messageCharacteristic(getMessages, setMessage)],
characteristics: [this.messageCharacteristic()],
});
}

Expand Down Expand Up @@ -75,23 +78,22 @@ export default class BluetoothPeripheral implements Task {
* @param setMessage
* @returns
*/
private messageCharacteristic(
getMessages: GetMessages,
setMessage: SetMessage
): Characteristic {
private messageCharacteristic(): Characteristic {
return new Characteristic({
uuid: MESSAGE_CHARACTERISTIC_UUID,
properties: ['read', 'write'],
permissions: ['readable', 'writeable'],
onReadRequest: async (offset?: number) => {
console.log(`Read offset ${offset}`);
const byteArr = Messages.encode(
Messages.fromJSON({ messages: getMessages() })
Messages.fromJSON({ messages: await this.storage.getMessages('all') })
).finish();
return fromByteArray(byteArr);
},
onWriteRequest: async (value: string, offset?: number) => {
console.log(`Write offset ${offset}`);
for (let message of Messages.decode(toByteArray(value)).messages) {
setMessage(message);
await this.storage.setMessage(message);
}
},
});
Expand Down
1 change: 1 addition & 0 deletions app/src/const.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const TESTING = false;
Loading

0 comments on commit d4e4e22

Please sign in to comment.