Skip to content

Commit 523dfe4

Browse files
committed
[ECO-5517] Refactored Adapter implementation, moved to liveobjects Helpers
- Removed unnecessary implementation from Adapter, made it clean - Updated unit tests/mocks accordingly
1 parent 0ac1e1a commit 523dfe4

5 files changed

Lines changed: 46 additions & 119 deletions

File tree

lib/src/main/java/io/ably/lib/objects/Adapter.java

Lines changed: 1 addition & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,10 @@
22

33
import io.ably.lib.realtime.AblyRealtime;
44
import io.ably.lib.realtime.ChannelBase;
5-
import io.ably.lib.realtime.ChannelState;
6-
import io.ably.lib.realtime.CompletionListener;
75
import io.ably.lib.transport.ConnectionManager;
86
import io.ably.lib.types.AblyException;
9-
import io.ably.lib.types.ChannelMode;
10-
import io.ably.lib.types.ChannelOptions;
117
import io.ably.lib.types.ClientOptions;
128
import io.ably.lib.types.ErrorInfo;
13-
import io.ably.lib.types.ProtocolMessage;
149
import io.ably.lib.util.Log;
1510
import org.jetbrains.annotations.NotNull;
1611

@@ -22,54 +17,6 @@ public Adapter(@NotNull AblyRealtime ably) {
2217
this.ably = ably;
2318
}
2419

25-
@Override
26-
public void setChannelSerial(@NotNull String channelName, @NotNull String channelSerial) {
27-
if (ably.channels.containsKey(channelName)) {
28-
ably.channels.get(channelName).properties.channelSerial = channelSerial;
29-
} else {
30-
Log.e(TAG, "setChannelSerial(): channel not found: " + channelName);
31-
}
32-
}
33-
34-
@Override
35-
public void send(@NotNull ProtocolMessage msg, @NotNull CompletionListener listener) throws AblyException {
36-
// Always queue LiveObjects messages to ensure reliable state synchronization and proper acknowledgment
37-
ably.connection.connectionManager.send(msg, true, listener);
38-
}
39-
40-
@Override
41-
public int maxMessageSizeLimit() {
42-
return ably.connection.connectionManager.maxMessageSize;
43-
}
44-
45-
@Override
46-
public ChannelMode[] getChannelModes(@NotNull String channelName) {
47-
if (ably.channels.containsKey(channelName)) {
48-
// RTO2a - channel.modes is only populated on channel attachment, so use it only if it is set
49-
ChannelMode[] modes = ably.channels.get(channelName).getModes();
50-
if (modes != null) {
51-
return modes;
52-
}
53-
// RTO2b - otherwise as a best effort use user provided channel options
54-
ChannelOptions options = ably.channels.get(channelName).getOptions();
55-
if (options != null && options.hasModes()) {
56-
return options.modes;
57-
}
58-
return null;
59-
}
60-
Log.e(TAG, "getChannelMode(): channel not found: " + channelName);
61-
return null;
62-
}
63-
64-
@Override
65-
public ChannelState getChannelState(@NotNull String channelName) {
66-
if (ably.channels.containsKey(channelName)) {
67-
return ably.channels.get(channelName).state;
68-
}
69-
Log.e(TAG, "getChannelState(): channel not found: " + channelName);
70-
return null;
71-
}
72-
7320
@Override
7421
public @NotNull ClientOptions getClientOptions() {
7522
return ably.options;
@@ -86,7 +33,7 @@ public long getTime() throws AblyException {
8633
}
8734

8835
@Override
89-
public ChannelBase getChannel(@NotNull String channelName) throws AblyException {
36+
public @NotNull ChannelBase getChannel(@NotNull String channelName) throws AblyException {
9037
if (ably.channels.containsKey(channelName)) {
9138
return ably.channels.get(channelName);
9239
} else {
Lines changed: 1 addition & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,13 @@
11
package io.ably.lib.objects;
22

33
import io.ably.lib.realtime.ChannelBase;
4-
import io.ably.lib.realtime.ChannelState;
5-
import io.ably.lib.realtime.CompletionListener;
64
import io.ably.lib.transport.ConnectionManager;
75
import io.ably.lib.types.AblyException;
8-
import io.ably.lib.types.ChannelMode;
96
import io.ably.lib.types.ClientOptions;
10-
import io.ably.lib.types.ProtocolMessage;
117
import org.jetbrains.annotations.Blocking;
128
import org.jetbrains.annotations.NotNull;
13-
import org.jetbrains.annotations.Nullable;
149

1510
public interface LiveObjectsAdapter {
16-
/**
17-
* Sends a protocol message to its intended recipient.
18-
* This method transmits a protocol message, allowing for queuing events if necessary,
19-
* and notifies the provided listener upon the success or failure of the send operation.
20-
*
21-
* @param msg the protocol message to send.
22-
* @param listener a listener to be notified of the success or failure of the send operation.
23-
* @throws AblyException if an error occurs during the send operation.
24-
*/
25-
void send(@NotNull ProtocolMessage msg, @NotNull CompletionListener listener) throws AblyException;
26-
27-
/**
28-
* Sets the channel serial for a specific channel.
29-
* @param channelName the name of the channel for which to set the serial
30-
* @param channelSerial the serial to set for the channel
31-
*/
32-
void setChannelSerial(@NotNull String channelName, @NotNull String channelSerial);
33-
34-
/**
35-
* Retrieves the maximum message size allowed for the messages.
36-
* This method returns the maximum size in bytes that a message can have.
37-
*
38-
* @return the maximum message size limit in bytes.
39-
*/
40-
int maxMessageSizeLimit();
41-
42-
/**
43-
* Retrieves the channel modes for a specific channel.
44-
* This method returns the modes that are set for the specified channel.
45-
*
46-
* @param channelName the name of the channel for which to retrieve the modes
47-
* @return the array of channel modes for the specified channel, or null if the channel is not found
48-
* Spec: RTO2a, RTO2b
49-
*/
50-
@Nullable ChannelMode[] getChannelModes(@NotNull String channelName);
51-
52-
/**
53-
* Retrieves the current state of a specific channel.
54-
* This method returns the state of the specified channel, which indicates its connection status.
55-
*
56-
* @param channelName the name of the channel for which to retrieve the state
57-
* @return the current state of the specified channel, or null if the channel is not found
58-
*/
59-
@Nullable ChannelState getChannelState(@NotNull String channelName);
60-
6111
/**
6212
* Retrieves the client options configured for the Ably client.
6313
* Used to access client configuration parameters such as echoMessages setting
@@ -91,6 +41,6 @@ public interface LiveObjectsAdapter {
9141
* @return the ChannelBase instance for the specified channel
9242
* @throws AblyException if the channel is not found or cannot be retrieved
9343
*/
94-
ChannelBase getChannel(@NotNull String channelName) throws AblyException;
44+
@NotNull ChannelBase getChannel(@NotNull String channelName) throws AblyException;
9545
}
9646

live-objects/src/main/kotlin/io/ably/lib/objects/Helpers.kt

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import kotlin.coroutines.resumeWithException
1515
*/
1616
internal suspend fun LiveObjectsAdapter.sendAsync(message: ProtocolMessage) = suspendCancellableCoroutine { continuation ->
1717
try {
18-
this.send(message, object : CompletionListener {
18+
connectionManager.send(message, clientOptions.queueMessages, object : CompletionListener {
1919
override fun onSuccess() {
2020
continuation.resume(Unit)
2121
}
@@ -31,7 +31,7 @@ internal suspend fun LiveObjectsAdapter.sendAsync(message: ProtocolMessage) = su
3131

3232
internal suspend fun LiveObjectsAdapter.attachAsync(channelName: String) = suspendCancellableCoroutine { continuation ->
3333
try {
34-
this.getChannel(channelName).attach(object : CompletionListener {
34+
getChannel(channelName).attach(object : CompletionListener {
3535
override fun onSuccess() {
3636
continuation.resume(Unit)
3737
}
@@ -45,11 +45,38 @@ internal suspend fun LiveObjectsAdapter.attachAsync(channelName: String) = suspe
4545
}
4646
}
4747

48+
/**
49+
* Retrieves the channel modes for a specific channel.
50+
* This method returns the modes that are set for the specified channel.
51+
*
52+
* @param channelName the name of the channel for which to retrieve the modes
53+
* @return the array of channel modes for the specified channel, or null if the channel is not found
54+
* Spec: RTO2a, RTO2b
55+
*/
56+
internal fun LiveObjectsAdapter.getChannelModes(channelName: String): Array<ChannelMode>? {
57+
val channel = getChannel(channelName)
58+
59+
// RTO2a - channel.modes is only populated on channel attachment, so use it only if it is set
60+
channel.modes?.let { modes ->
61+
if (modes.isNotEmpty()) {
62+
return modes
63+
}
64+
}
65+
66+
// RTO2b - otherwise as a best effort use user provided channel options
67+
channel.options?.let { options ->
68+
if (options.hasModes()) {
69+
return options.modes
70+
}
71+
}
72+
return null
73+
}
74+
4875
/**
4976
* Spec: RTO15d
5077
*/
5178
internal fun LiveObjectsAdapter.ensureMessageSizeWithinLimit(objectMessages: Array<ObjectMessage>) {
52-
val maximumAllowedSize = maxMessageSizeLimit()
79+
val maximumAllowedSize = connectionManager.maxMessageSize
5380
val objectsTotalMessageSize = objectMessages.sumOf { it.size() }
5481
if (objectsTotalMessageSize > maximumAllowedSize) {
5582
throw ablyException("ObjectMessages size $objectsTotalMessageSize exceeds maximum allowed size of $maximumAllowedSize bytes",
@@ -61,11 +88,12 @@ internal fun LiveObjectsAdapter.setChannelSerial(channelName: String, protocolMe
6188
if (protocolMessage.action != ProtocolMessage.Action.`object`) return
6289
val channelSerial = protocolMessage.channelSerial
6390
if (channelSerial.isNullOrEmpty()) return
64-
setChannelSerial(channelName, channelSerial)
91+
getChannel(channelName).properties.channelSerial = channelSerial
6592
}
6693

6794
internal suspend fun LiveObjectsAdapter.ensureAttached(channelName: String) {
68-
when (val currentChannelStatus = this.getChannelState(channelName)) {
95+
val channel = getChannel(channelName)
96+
when (val currentChannelStatus = channel.state) {
6997
ChannelState.initialized -> attachAsync(channelName)
7098
ChannelState.attached -> return
7199
ChannelState.attaching -> {
@@ -80,7 +108,7 @@ internal suspend fun LiveObjectsAdapter.ensureAttached(channelName: String) {
80108
}
81109
}
82110
}
83-
if (this.getChannelState(channelName) == ChannelState.attached) {
111+
if (channel.state == ChannelState.attached) {
84112
attachDeferred.complete(Unit)
85113
}
86114
attachDeferred.await()
@@ -119,7 +147,7 @@ internal fun LiveObjectsAdapter.throwIfMissingChannelMode(channelName: String, c
119147
}
120148

121149
internal fun LiveObjectsAdapter.throwIfInChannelState(channelName: String, channelStates: Array<ChannelState>) {
122-
val currentState = getChannelState(channelName)
150+
val currentState = getChannel(channelName).state
123151
if (currentState == null || channelStates.contains(currentState)) {
124152
throw ablyException("Channel is in invalid state: $currentState", ErrorCode.ChannelStateError)
125153
}

live-objects/src/test/kotlin/io/ably/lib/objects/unit/ObjectMessageSizeTest.kt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import io.ably.lib.objects.ensureMessageSizeWithinLimit
1212
import io.ably.lib.objects.size
1313
import io.ably.lib.transport.Defaults
1414
import io.ably.lib.types.AblyException
15-
import io.mockk.every
1615
import io.mockk.mockk
1716
import kotlinx.coroutines.test.runTest
1817
import org.junit.Test
@@ -23,9 +22,9 @@ class ObjectMessageSizeTest {
2322

2423
@Test
2524
fun testObjectMessageSizeWithinLimit() = runTest {
26-
val mockAdapter = mockk<LiveObjectsAdapter>()
27-
every { mockAdapter.maxMessageSizeLimit() } returns Defaults.maxMessageSize // 64 kb
28-
assertEquals(65536, mockAdapter.maxMessageSizeLimit())
25+
val mockAdapter = mockk<LiveObjectsAdapter>(relaxed = true)
26+
mockAdapter.connectionManager.maxMessageSize = Defaults.maxMessageSize // 64 kb
27+
assertEquals(65536, mockAdapter.connectionManager.maxMessageSize)
2928

3029
// ObjectMessage with all size-contributing fields
3130
val objectMessage = ObjectMessage(
@@ -148,8 +147,9 @@ class ObjectMessageSizeTest {
148147

149148
@Test
150149
fun testObjectMessageSizeAboveLimit() = runTest {
151-
val mockAdapter = mockk<LiveObjectsAdapter>()
152-
every { mockAdapter.maxMessageSizeLimit() } returns Defaults.maxMessageSize // 64 kb
150+
val mockAdapter = mockk<LiveObjectsAdapter>(relaxed = true)
151+
mockAdapter.connectionManager.maxMessageSize = Defaults.maxMessageSize // 64 kb
152+
assertEquals(65536, mockAdapter.connectionManager.maxMessageSize)
153153

154154
// Create ObjectMessage with dummy data that results in size 60kb
155155
val objectMessage1 = ObjectMessage(

live-objects/src/test/kotlin/io/ably/lib/objects/unit/TestHelpers.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,9 @@ internal fun getMockRealtimeChannel(
4545
}
4646

4747
internal fun getMockLiveObjectsAdapter(): LiveObjectsAdapter {
48-
return mockk<LiveObjectsAdapter>(relaxed = true)
48+
val mockkAdapter = mockk<LiveObjectsAdapter>(relaxed = true)
49+
every { mockkAdapter.getChannel(any()) } returns getMockRealtimeChannel("testChannelName")
50+
return mockkAdapter
4951
}
5052

5153
internal fun getMockObjectsPool(): ObjectsPool {

0 commit comments

Comments
 (0)