Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Resolves #170 - Return error on monitor disconnection #175

Conversation

bartoszstelmaszuk
Copy link
Contributor

@bartoszstelmaszuk bartoszstelmaszuk commented Oct 26, 2017

Resolves #170 so the library returns error on monitorDisconnection to the user

@bartoszstelmaszuk bartoszstelmaszuk changed the base branch from master to 5.0-dev October 26, 2017 10:40
@@ -255,8 +255,8 @@ public class BluetoothManager {
/// - parameter peripheral: The `Peripheral` to which the `BluetoothManager` is either trying to
/// connect or has already connected.
/// - returns: `Single` which emits next event when peripheral successfully cancelled connection.
public func cancelPeripheralConnection(_ peripheral: Peripheral) -> Single<Peripheral> {
let observable = Observable<Peripheral>.create { [weak self] observer in
public func cancelPeripheralConnection(_ peripheral: Peripheral) -> Observable<(Peripheral, BluetoothError?)> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we could introduce a wrapper type to indicate that the peripheral might be returned without error?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you mean by that? Optional type indicates that there may or may not be an error related to disconnection. How would you name your wrapper type? Will it be an enum?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking through library i found that in most cases a tuple is used instead of wrapper type. I decided to follow the current style. Don't you think that optionality on BluetoothError indicates enough that the observable can return without error?

@@ -265,7 +265,7 @@ public class BluetoothManager {
strongSelf.centralManager.cancelPeripheralConnection(peripheral.peripheral)
return disposable
}
return ensure(.poweredOn, observable: observable).asSingle()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason for dropping the Single here? Can we emit multiple events now?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! Already repairing it.

public func monitorDisconnection(for peripheral: Peripheral) -> Observable<(Peripheral, BluetoothError?)> {
return monitorPeripheral(
on: delegateWrapper.rx_didDisconnectPeripheral.map { (_, error) in
throw BluetoothError.peripheralDisconnectionFailed(peripheral, error)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I might not read it correctly, but is there a reason for why you're ignoring the peripheral returned from peripheralAction observable here? It seems to me that the logic deciding which instance should be returned in the error should be kept in one place and monitorPeripheral is better place in my opinion. Right now it's been done twice: in monitorDisconnection method and monitorPeripheral method.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code is not behaving correctly. We shouldn't throw error there.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1. In the issue I said that error should be emitted in the resulting observable next events, not as an error on stream.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

corrected throwing. It should be mapped as you mentioned.

@@ -255,8 +255,8 @@ public class BluetoothManager {
/// - parameter peripheral: The `Peripheral` to which the `BluetoothManager` is either trying to
/// connect or has already connected.
/// - returns: `Single` which emits next event when peripheral successfully cancelled connection.
public func cancelPeripheralConnection(_ peripheral: Peripheral) -> Single<Peripheral> {
let observable = Observable<Peripheral>.create { [weak self] observer in
public func cancelPeripheralConnection(_ peripheral: Peripheral) -> Observable<(Peripheral, BluetoothError?)> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you mean by that? Optional type indicates that there may or may not be an error related to disconnection. How would you name your wrapper type? Will it be an enum?

return monitorPeripheral(
on: delegateWrapper.rx_didConnectPeripheral.map { ($0, nil) },
peripheral: peripheral
).map { $0.0 }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we creating tuple to just drop it at the end?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it is to use monitorPeripheral function in both connection and disconnection functions.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not convinced to this — It's right now kind of artificial way to do this generalization. Could we find some other approach to implement this? This tuple creation reason is complicated and deserves comment at least. The best would be to find other way or just drop helper function.

@@ -78,6 +79,8 @@ extension BluetoothError: CustomStringConvertible {
return "Connection error has occured: \(err?.localizedDescription ?? "-")"
case let .peripheralDisconnected(_, err):
return "Connection error has occured: \(err?.localizedDescription ?? "-")"
case let .peripheralDisconnectionFailed(_, err):
return "Connection error has occured: \(err?.localizedDescription ?? "-")"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to documentation disconnection cannot fail. So there shouldn't be any error related to that.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

public func monitorDisconnection(for peripheral: Peripheral) -> Observable<(Peripheral, BluetoothError?)> {
return monitorPeripheral(
on: delegateWrapper.rx_didDisconnectPeripheral.map { (_, error) in
throw BluetoothError.peripheralDisconnectionFailed(peripheral, error)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code is not behaving correctly. We shouldn't throw error there.

}

func monitorPeripheral(on peripheralAction: Observable<CBPeripheral>, peripheral: Peripheral)
-> Observable<Peripheral> {
func monitorPeripheral(on peripheralAction: Observable<(CBPeripheral, BluetoothError?)>, peripheral: Peripheral)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if this function is worth to share it between connected/disconnected events.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in my opinion it is. If we would like to separate it instead of two easy maps we would have to implement logic of filtering and mapping on stream of pheripheralAction with ensuring poweredOn state in both function monitorConnection and monitorDisconnection

@@ -92,7 +92,7 @@ public class Peripheral {
/// that physical connection will be closed immediately as well and all pending commands will not be executed.
///
/// - returns: `Single` which emits next event when peripheral successfully cancelled connection.
public func cancelConnection() -> Single<Peripheral> {
public func cancelConnection() -> Observable<(Peripheral, BluetoothError?)> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why observable?

@bartoszstelmaszuk bartoszstelmaszuk changed the title Return error on monitor disconnection Resolves #170 - Return error on monitor disconnection Oct 26, 2017
Copy link
Contributor

@Kacper20 Kacper20 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couple of more comments. We're getting there :)

@@ -92,7 +92,7 @@ public class Peripheral {
/// that physical connection will be closed immediately as well and all pending commands will not be executed.
///
/// - returns: `Single` which emits next event when peripheral successfully cancelled connection.
public func cancelConnection() -> Single<Peripheral> {
public func cancelConnection() -> Single<(Peripheral)> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need parentheses here.

@@ -265,7 +265,7 @@ public class BluetoothManager {
strongSelf.centralManager.cancelPeripheralConnection(peripheral.peripheral)
return disposable
}
return ensure(.poweredOn, observable: observable).asSingle()
return ensure(.poweredOn, observable: observable).asSingle().map { $0.0 }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would move map to the new line for better readability

/// - Returns: Observable which emits next events when `peripheral` was disconnected.
public func monitorDisconnection(for peripheral: Peripheral) -> Observable<Peripheral> {
return monitorPeripheral(on: delegateWrapper.rx_didDisconnectPeripheral.map { $0.0 }, peripheral: peripheral)
/// - Returns: Observable which emits next events when `peripheral` was disconnected and error which is
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would say: Returns: Observable which emits next events when `Peripheral` instance was disconnected. It provides optional error which may contain more information about the cause of the disconnection if it wasn't the `cancelConnection` call

return monitorPeripheral(on: delegateWrapper.rx_didDisconnectPeripheral.map { $0.0 }, peripheral: peripheral)
/// - Returns: Observable which emits next events when `peripheral` was disconnected and error which is
/// a disconnection reason when it was caused by 'peripheral' otherwise it's nil.
public typealias DisconnectionReason = Error?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

type alias should be above the documentation comments. Right now docs refer to type alias not to a function. Additionaly it should be DisconnectionReason = Error. Then in interface user sees immediately that it's optional — without looking at type alias definition.

func monitorPeripheral(on peripheralAction: Observable<CBPeripheral>, peripheral: Peripheral)
-> Observable<Peripheral> {
func monitorPeripheral(on peripheralAction: Observable<(CBPeripheral, DisconnectionReason)>, peripheral: Peripheral)
-> Observable<(Peripheral, Error?)> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could also use DisconnectionReason here instead of an Error

return monitorPeripheral(
on: delegateWrapper.rx_didConnectPeripheral.map { ($0, nil) },
peripheral: peripheral
).map { $0.0 }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not convinced to this — It's right now kind of artificial way to do this generalization. Could we find some other approach to implement this? This tuple creation reason is complicated and deserves comment at least. The best would be to find other way or just drop helper function.

@bartoszstelmaszuk bartoszstelmaszuk force-pushed the return_error_on_monitor_disconnection branch from 62b3a11 to 57a1192 Compare October 27, 2017 11:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants