react-native-studia
Version:
819 lines (661 loc) • 29.7 kB
JavaScript
// @flow
'use strict'
import {
State,
type ErrorCodeMessageMapping,
Subscription,
StudiaManagerOptions,
Carriers,
Network,
Socket,
type Subscriber,
type ObservableId,
type ServalId,
PeerState,
Feed
} from './Types';
import {
NetworkModule,
IdentityModule,
EventEmitter
} from './StudiaModules';
import type {
NativeIdentity,
NativeFeed,
NativePeer,
NativeMessage
} from './StudiaModules'
import {
parseError,
ErrorCodeMessage,
StudiaError,
ErrorCode
} from './StudiaError';
import { Identity } from './Identity'
import { Peer } from './Peer'
import { MyFeed } from './MyFeed'
import { Message } from './Message'
import { Carrier } from './Carrier'
export class StudiaManager {
_uniqueId: number
_activePromises: { [id: string]: (error: StudiaError) => void }
_errorCodesToMessagesMapping: ErrorCodeMessageMapping
_eventEmitter: EventEmitter
_activeSubscriptions: { [id: string]: Subscription }
_activeSockets: { [id: string]: Socket<any> }
carrier: Carrier
constructor(options: StudiaManagerOptions = {}) {
this._eventEmitter = new EventEmitter(NetworkModule)
this._uniqueId = 0
this._activePromises = {}
this._activeSubscriptions = {}
this._activeSockets = {}
this._errorCodesToMessagesMapping = options.errorCodesToMessagesMapping
? options.errorCodesToMessagesMapping
: ErrorCodeMessage
this.carrier = new Carrier(this)
}
_destroyPromises() {
const destroyedError = new StudiaError(
{
errorCode: ErrorCode.StudiaManagerDestroyed,
//reason: (null : ?string),
},
this._errorCodesToMessagesMapping
)
for (const id in this._activePromises) {
this._activePromises[id](destroyedError)
}
}
_destroySubscriptions() {
for (const id in this._activeSubscriptions) {
this._activeSubscriptions[id].remove()
}
}
destroy() {
this._destroySubscriptions()
this._destroyPromises()
}
_nextUniqueID(): string {
this._uniqueId += 1
return this._uniqueId.toString()
}
async _callPromise<T>(promise: Promise<T>): Promise<T> {
const id = this._nextUniqueID()
try {
const destroyPromise = new Promise((resolve, reject) => {
this._activePromises[id] = reject
})
const value = await Promise.race([destroyPromise, promise])
delete this._activePromises[id]
return value
} catch (error) {
delete this._activePromises[id]
throw parseError(error.message, this._errorCodesToMessagesMapping)
}
}
_stopObserving(observerId: ObservableId) {
IdentityModule.stopObserving(observerId)
}
async enable(carrier: $Values<typeof Carriers>) : Promise<Network> {
switch(carrier) {
case Carriers.Ble:
return await this._callPromise(NetworkModule.setBleEnable());
case Carriers.Wifi:
return await this._callPromise(NetworkModule.setWifiEnable());
case Carriers.Hotspot:
return await this._callPromise(NetworkModule.setHotspotEnable());
default:
return await this._callPromise(NetworkModule.setWifiDirectEnable());
}
}
async disable(carrier: $Values<typeof Carriers>) : Promise<void> {
switch(carrier) {
case Carriers.Ble:
return await this._callPromise(NetworkModule.setBleDisable());
case Carriers.Wifi:
return await this._callPromise(NetworkModule.setWifiDisable());
case Carriers.Hotspot:
return await this._callPromise(NetworkModule.setHotspotDisable());
default:
return await this._callPromise(NetworkModule.setWifiDirectDisable());
}
}
state(carrier: $Values<typeof Carriers>) : Promise<$Values<typeof State>> {
return this._callPromise(NetworkModule.getState(carrier));
}
async createIdentity(identityName: string) : Promise<Identity> {
const nativeIdentity = await this._callPromise(IdentityModule.createIdentity(identityName))
return new Identity(nativeIdentity, this)
}
async getIdentities() : Promise<Array<Identity>> {
const nativeIdentities = await this._callPromise(IdentityModule.getIdentities())
return nativeIdentities.map((nativeIdentity: NativeIdentity) => {
return new Identity(nativeIdentity, this)
})
}
async updateIdentity(identityKey: Subscriber, identityName: string) : Promise<Identity> {
const nativeIdentity = await this._callPromise(IdentityModule.updateIdentity(identityKey, identityName))
return new Identity(nativeIdentity, this)
}
getFeedSocket(identityId: Subscriber, callback: (error: ?StudiaError) => void): Socket<MyFeed> {
const socketId = this._nextUniqueID()
var socket: Socket<MyFeed>
this._callPromise(IdentityModule.runFeedObservable(identityId))
.catch((error: StudiaError) => {
callback(error)
})
socket = {
send: async (message) => {
const nativeFeed = await this._callPromise(IdentityModule.sendFeed(message))
return new MyFeed(nativeFeed, this)
},
stop: () => {
if(this._activeSockets[socketId] != null) {
delete this._activeSockets[socketId]
IdentityModule.stopFeedObservable()
}
}
}
this._activeSockets[socketId] = socket
return socket
}
getFeeds(identityId: Subscriber, callback: (error: ?StudiaError, feeds: ?Array<MyFeed>) => void) : Subscription {
const subscriptionId = this._nextUniqueID()
var subscription : Subscription
this._callPromise(IdentityModule.getFeeds(identityId, subscriptionId))
.then((feeds) => {
const jsFeeds = feeds.map((nativeFeed: NativeFeed) => {
return new MyFeed(nativeFeed, this)
})
callback(null, jsFeeds)
}, (error: StudiaError) => {
callback(error, null)
})
subscription = {
remove: () => {
if (this._activeSubscriptions[subscriptionId] != null) {
delete this._activeSubscriptions[subscriptionId]
this._stopObserving(subscriptionId)
}
}
}
this._activeSubscriptions[subscriptionId] = subscription
return subscription
}
getContacts(identityId: Subscriber, callback: (error: ?StudiaError, peers: ?Array<Peer>) => void) : Subscription {
const subscriptionId = this._nextUniqueID()
var subscription : Subscription
this._callPromise(IdentityModule.getContacts(identityId, subscriptionId))
.then((peers) => {
const jsPeers = peers.map((nativePeer: NativePeer) => {
return new Peer(nativePeer, this)
})
callback(null, jsPeers)
}, (error: StudiaError) => {
callback(error, null)
})
subscription = {
remove: () => {
if (this._activeSubscriptions[subscriptionId] != null) {
delete this._activeSubscriptions[subscriptionId]
this._stopObserving(subscriptionId)
}
}
}
this._activeSubscriptions[subscriptionId] = subscription
return subscription
}
getBlocklist(identityId: Subscriber, callback: (error: ?StudiaError, peers: ?Array<Peer>) => void) : Subscription {
const subscriptionId = this._nextUniqueID()
var subscription : Subscription
this._callPromise(IdentityModule.getBlocklist(identityId, subscriptionId))
.then((peers) => {
const jsPeers = peers.map((nativePeer: NativePeer) => {
return new Peer(nativePeer, this)
})
callback(null, jsPeers)
}, (error: StudiaError) => {
callback(error, null)
})
subscription = {
remove: () => {
if (this._activeSubscriptions[subscriptionId] != null) {
delete this._activeSubscriptions[subscriptionId]
this._stopObserving(subscriptionId)
}
}
}
this._activeSubscriptions[subscriptionId] = subscription
return subscription
}
// getPeers(identityId: Subscriber, callback: (error: ?StudiaError, peers: ?Array<Peer>) => void) : Subscription {
// const subscriptionId = this._nextUniqueID()
// var subscription : Subscription
// this._callPromise(IdentityModule.getPeers(identityId, subscriptionId))
// .then((peers) => {
// const jsPeers = peers.map((nativePeer: NativePeer) => {
// return new Peer(nativePeer, this)
// })
// callback(null, jsPeers)
// }, (error: StudiaError) => {
// callback(error, null)
// })
// subscription = {
// remove: () => {
// if (this._activeSubscriptions[subscriptionId] != null) {
// delete this._activeSubscriptions[subscriptionId]
// this._stopObserving(subscriptionId)
// }
// }
// }
// this._activeSubscriptions[subscriptionId] = subscription
// return subscription
// }
getNearby(identityId: Subscriber, callback: (error: ?StudiaError, peers: ?Array<Peer>) => void) : Subscription {
const subscriptionId = this._nextUniqueID()
var subscription : Subscription
this._callPromise(IdentityModule.getNearby(identityId, subscriptionId))
.then((peers) => {
const jsPeers = peers.map((nativePeer: NativePeer) => {
return new Peer(nativePeer, this)
})
callback(null, jsPeers)
}, (error: StudiaError) => {
callback(error, null)
})
subscription = {
remove: () => {
if (this._activeSubscriptions[subscriptionId] != null) {
delete this._activeSubscriptions[subscriptionId]
this._stopObserving(subscriptionId)
}
}
}
this._activeSubscriptions[subscriptionId] = subscription
return subscription
}
getPeersConversations(identityId: Subscriber, callback: (error: ?StudiaError, peers: ?Array<Peer>) => void) : Subscription {
const subscriptionId = this._nextUniqueID()
var subscription : Subscription
this._callPromise(IdentityModule.getPeersConversations(identityId, subscriptionId))
.then((peers) => {
const jsPeers = peers.map((nativePeer: NativePeer) => {
return new Peer(nativePeer, this)
})
callback(null, jsPeers)
}, (error: StudiaError) => {
callback(error, null)
})
subscription = {
remove: () => {
if (this._activeSubscriptions[subscriptionId] != null) {
delete this._activeSubscriptions[subscriptionId]
this._stopObserving(subscriptionId)
}
}
}
this._activeSubscriptions[subscriptionId] = subscription
return subscription
}
getPeersRequests(identityId: Subscriber, callback: (error: ?StudiaError, peers: ?Array<Peer>) => void) : Subscription {
const subscriptionId = this._nextUniqueID()
var subscription : Subscription
this._callPromise(IdentityModule.getPeersRequests(identityId, subscriptionId))
.then((peers) => {
const jsPeers = peers.map((nativePeer: NativePeer) => {
return new Peer(nativePeer, this)
})
callback(null, jsPeers)
}, (error: StudiaError) => {
callback(error, null)
})
subscription = {
remove: () => {
if (this._activeSubscriptions[subscriptionId] != null) {
delete this._activeSubscriptions[subscriptionId]
this._stopObserving(subscriptionId)
}
}
}
this._activeSubscriptions[subscriptionId] = subscription
return subscription
}
getPeerFeeds(servalId: ServalId, callback: (error: ?StudiaError, feeds: ?Array<Feed>) => void) : Subscription {
const subscriptionId = this._nextUniqueID()
var subscription : Subscription
this._callPromise(IdentityModule.getPeerFeeds(servalId, subscriptionId))
.then((nativeFeeds) => {
callback(null, nativeFeeds)
}, (error: StudiaError) => {
callback(error, null)
})
subscription = {
remove: () => {
if (this._activeSubscriptions[subscriptionId] != null) {
delete this._activeSubscriptions[subscriptionId]
this._stopObserving(subscriptionId)
}
}
}
this._activeSubscriptions[subscriptionId] = subscription
return subscription
}
getPrivateMessages(identityId: Subscriber, peerId: Subscriber, callback: (error: ?StudiaError, messages: ?Array<Message>) => void) : Subscription {
const subscriptionId = this._nextUniqueID()
var subscription : Subscription
this._callPromise(IdentityModule.getPrivateMessages(identityId, peerId, subscriptionId))
.then((messages) => {
const jsMessage = messages.map((nativeMessage: NativeMessage) => {
return new Message(nativeMessage, this)
})
callback(null, jsMessage)
}, (error: StudiaError) => {
callback(error, null)
})
subscription = {
remove: () => {
if (this._activeSubscriptions[subscriptionId] != null) {
delete this._activeSubscriptions[subscriptionId]
this._stopObserving(subscriptionId)
}
}
}
this._activeSubscriptions[subscriptionId] = subscription
return subscription
}
async follow(identityId: Subscriber, peerId: Subscriber) : Promise<void> {
return await this._callPromise(IdentityModule.follow(identityId, peerId))
}
async block(identityId: Subscriber, peerId: Subscriber) : Promise<void> {
return await this._callPromise(IdentityModule.block(identityId, peerId))
}
async ignore(identityId: Subscriber, peerId: Subscriber) : Promise<void> {
return await this._callPromise(IdentityModule.ignore(identityId, peerId))
}
async getPeerState(identityId: Subscriber, peerId: Subscriber) : Promise<$Keys<typeof PeerState>> {
return await this._callPromise(IdentityModule.getPeerState(identityId, peerId))
}
// async sendMessage(identityId: Subscriber, peerId: Subscriber, message: string) : Promise<Message> {
// const nativeMessage = await this._callPromise(IdentityModule.sendMessage(identityId, peerId, message))
// return new Message(nativeMessage, this)
// }
getMessageSocket(identityId: Subscriber, peerId: Subscriber, callback: (error: ?StudiaError) => void): Socket<Message> {
const socketId = this._nextUniqueID()
var socket: Socket<Message>
this._callPromise(IdentityModule.runMessageObservable(identityId, peerId))
.catch((error: StudiaError) => {
callback(error)
})
socket = {
send: async (message) => {
const nativeMessage = await this._callPromise(IdentityModule.sendMessage(message))
return new Message(nativeMessage, this)
},
stop: () => {
if(this._activeSockets[socketId] != null) {
delete this._activeSockets[socketId]
IdentityModule.stopMessageObservable()
}
}
}
this._activeSockets[socketId] = socket
return socket
}
onStateChange(carrier: $Values<typeof Carriers>, listener: (newState: $Keys<typeof State>) => void, emitCurrentState: boolean = false) : Subscription {
const event = this._handleSubscriptionListener(carrier)
const subscription : Subscription = this._eventEmitter.addListener(event, listener)
const subscriptionId = this._nextUniqueID()
if(emitCurrentState) {
this.state(carrier).then((state) => {
listener(state)
})
}
return this._handleSubscriptionState(
subscription,
subscriptionId
)
}
_handleSubscriptionListener(
carrier: $Values<typeof Carriers>
) : string {
switch(carrier) {
case Carriers.Wifi:
return NetworkModule.WifiStateChangeEvent
case Carriers.WifiDirect:
return NetworkModule.WifiDirectStateChangeEvent
case Carriers.Ble:
return NetworkModule.BleStateChangeEvent
default:
return NetworkModule.HotspotStateChangeEvent
}
}
_handleSubscriptionState(subscription: Subscription, subscriptionId: string) : Subscription {
var wrappedSubscription: Subscription
wrappedSubscription = {
remove: () => {
if (this._activeSubscriptions[subscriptionId] != null) {
delete this._activeSubscriptions[subscriptionId]
subscription.remove()
}
}
}
this._activeSubscriptions[subscriptionId] = wrappedSubscription
return wrappedSubscription
}
onUnreadMessagesChanged(identityId: Subscriber, listener: (count: number) => void) : Subscription {
const subscription: Subscription = this._eventEmitter.addListener(IdentityModule.UnreadMessagesChanged, listener)
const id = this._nextUniqueID()
var wrappedSubscription: Subscription
this._callPromise(IdentityModule.getUnreadMessages(identityId, id))
.then((count) => {
listener(count)
})
wrappedSubscription = {
remove: () => {
if (this._activeSubscriptions[id] != null) {
delete this._activeSubscriptions[id]
this._stopObserving(id)
subscription.remove()
}
}
}
this._activeSubscriptions[id] = wrappedSubscription
return wrappedSubscription
}
onRequestMessagesChanged(identityId: Subscriber, listener: (count: number) => void) : Subscription {
const subscription: Subscription = this._eventEmitter.addListener(IdentityModule.RequestMessagesChanged, listener)
const id = this._nextUniqueID()
var wrappedSubscription: Subscription
this._callPromise(IdentityModule.getRequestMessages(identityId, id))
.then((count) => {
listener(count)
})
wrappedSubscription = {
remove: () => {
if (this._activeSubscriptions[id] != null) {
delete this._activeSubscriptions[id]
this._stopObserving(id)
subscription.remove()
}
}
}
this._activeSubscriptions[id] = wrappedSubscription
return wrappedSubscription
}
onNearbyPeersChanged(identityId: Subscriber, listener: (count: number) => void) : Subscription {
const subscription: Subscription = this._eventEmitter.addListener(IdentityModule.NearbyPeersChanged, listener)
const id = this._nextUniqueID()
var wrappedSubscription: Subscription
this._callPromise(IdentityModule.getNearbyPeers(identityId, id))
.then((count) => {
listener(count)
})
wrappedSubscription = {
remove: () => {
if (this._activeSubscriptions[id] != null) {
delete this._activeSubscriptions[id]
this._stopObserving(id)
subscription.remove()
}
}
}
this._activeSubscriptions[id] = wrappedSubscription
return wrappedSubscription
}
// onFeedAdded(listener: (feed: MyFeed) => void) : Subscription {
// const subscription: Subscription = this._eventEmitter.addListener(IdentityModule.FeedAddedEvent, listener)
// const id = this._nextUniqueID()
// var wrappedSubscription: Subscription
// wrappedSubscription = {
// remove: () => {
// if (this._activeSubscriptions[id] != null) {
// delete this._activeSubscriptions[id]
// subscription.remove()
// }
// }
// }
// this._activeSubscriptions[id] = wrappedSubscription
// return wrappedSubscription
// }
// onFeedReset(listener: (feeds: MyFeed[]) => void) : Subscription {
// const subscription: Subscription = this._eventEmitter.addListener(IdentityModule.FeedResetEvent, listener)
// const id = this._nextUniqueID()
// var wrappedSubscription: Subscription
// wrappedSubscription = {
// remove: () => {
// if (this._activeSubscriptions[id] != null) {
// delete this._activeSubscriptions[id]
// subscription.remove()
// }
// }
// }
// this._activeSubscriptions[id] = wrappedSubscription
// return wrappedSubscription
// }
onFeedAdded(listener: (feed: Feed) => void) : Subscription {
const subscription: Subscription = this._eventEmitter.addListener(IdentityModule.onFeedAddedEvent, listener)
const id = this._nextUniqueID()
var wrappedSubscription: Subscription
wrappedSubscription = {
remove: () => {
if (this._activeSubscriptions[id] != null) {
delete this._activeSubscriptions[id]
subscription.remove()
}
}
}
this._activeSubscriptions[id] = wrappedSubscription
return wrappedSubscription
}
// onFeedReset(listener: (feeds: Feed[]) => void) : Subscription {
// const subscription: Subscription = this._eventEmitter.addListener(IdentityModule.onFeedResetEvent, listener)
// const id = this._nextUniqueID()
// var wrappedSubscription: Subscription
// wrappedSubscription = {
// remove: () => {
// if (this._activeSubscriptions[id] != null) {
// delete this._activeSubscriptions[id]
// subscription.remove()
// }
// }
// }
// this._activeSubscriptions[id] = wrappedSubscription
// return wrappedSubscription
// }
onPeerFound(listener: (peer: Peer) => void) : Subscription {
const peerListener = (nativePeer : NativePeer) => {
let peer = new Peer(nativePeer, this)
listener(peer)
}
const subscription: Subscription = this._eventEmitter.addListener(IdentityModule.onPeerFoundEvent, peerListener)
const id = this._nextUniqueID()
var wrappedSubscription: Subscription
wrappedSubscription = {
remove: () => {
if (this._activeSubscriptions[id] != null) {
delete this._activeSubscriptions[id]
subscription.remove()
}
}
}
this._activeSubscriptions[id] = wrappedSubscription
return wrappedSubscription
}
onPeerUpdated(listener: (peer: Peer) => void) : Subscription {
const peerListener = (nativePeer : NativePeer) => {
let peer = new Peer(nativePeer, this)
listener(peer)
}
const subscription: Subscription = this._eventEmitter.addListener(IdentityModule.onPeerUpdatedEvent, peerListener)
const id = this._nextUniqueID()
var wrappedSubscription: Subscription
wrappedSubscription = {
remove: () => {
if (this._activeSubscriptions[id] != null) {
delete this._activeSubscriptions[id]
subscription.remove()
}
}
}
this._activeSubscriptions[id] = wrappedSubscription
return wrappedSubscription
}
onPeerReset(listener: (peers: Array<Peer>) => void) : Subscription {
const peerListener = (nativePeers : Array<NativePeer>) => {
let peers = nativePeers.map((nativePeer) => {return new Peer(nativePeer, this)})
listener(peers)
}
const subscription: Subscription = this._eventEmitter.addListener(IdentityModule.onPeersResetEvent, peerListener)
const id = this._nextUniqueID()
var wrappedSubscription: Subscription
wrappedSubscription = {
remove: () => {
if (this._activeSubscriptions[id] != null) {
delete this._activeSubscriptions[id]
subscription.remove()
}
}
}
this._activeSubscriptions[id] = wrappedSubscription
return wrappedSubscription
}
onMessageReceived(listener: (message: Message) => void) : Subscription {
const messageListener = (nativeMessage : NativeMessage) => {
const msg = new Message(nativeMessage, this)
listener(msg)
}
const subscription: Subscription = this._eventEmitter.addListener(IdentityModule.onMessageRecievedEvent, messageListener)
const id = this._nextUniqueID()
var wrappedSubscription: Subscription
wrappedSubscription = {
remove: () => {
if (this._activeSubscriptions[id] != null) {
delete this._activeSubscriptions[id]
subscription.remove()
}
}
}
this._activeSubscriptions[id] = wrappedSubscription
return wrappedSubscription
}
onMessageDelivered(listener: (message: Message) => void) : Subscription {
const messageListener = (nativeMessage : NativeMessage) => {
const msg = new Message(nativeMessage, this)
listener(msg)
}
const subscription: Subscription = this._eventEmitter.addListener(IdentityModule.onMessageDeliveredEvent, messageListener)
const id = this._nextUniqueID()
var wrappedSubscription: Subscription
wrappedSubscription = {
remove: () => {
if (this._activeSubscriptions[id] != null) {
delete this._activeSubscriptions[id]
subscription.remove()
}
}
}
this._activeSubscriptions[id] = wrappedSubscription
return wrappedSubscription
}
}