A Realtime Clone from Appwrite Flutter sdk. The purpose of this is to extend the capability and separate from sdk-generator
❗ In order to start using App Realtime Ext you must have the Flutter SDK installed on your machine.
Install via flutter pub add
:
dart pub add app_realtime_ext
App Realtime Ext comes with a built-in GitHub Actions workflow powered by Very Good Workflows but you can also add your preferred CI/CD solution.
Out of the box, on each pull request and push, the CI formats
, lints
, and tests
the code. This ensures the code remains consistent and behaves correctly as you add functionality or make changes. The project uses Very Good Analysis for a strict set of analysis options used by our team. Code coverage is enforced using the Very Good Workflows.
For first time users, install the very_good_cli:
dart pub global activate very_good_cli
To run all unit tests:
very_good test --coverage
To view the generated coverage report you can use lcov.
# Generate Coverage Report
genhtml coverage/lcov.info -o coverage/
# Open Coverage Report
open coverage/index.html
As I know, Appwrite Flutter SDK was generated by sdk-generator. It's a great tool to generate different SDKs for different languages. But, here is the problem. If we have to update some code in specific Appwrite SDK, it must be consistent with other SDKs. So, I decided to create this package by cloning and get only the Realtime related code from Appwrite Flutter SDK. This package is not generated by sdk-generator. It's a manual process to get the Realtime related code from Appwrite Flutter SDK. And I will maintain this package to keep it up-to-date with Appwrite Flutter SDK. Another reason is that we can extend the capability of Appwrite Flutter SDK by adding more features to this package.
import 'package:app_realtime_ext/app_realtime_ext.dart';
final RealtimeExt realtime = RealtimeExt();
realtime.initialize(client: client);
Note:
client
is an instance ofClient
from Appwrite Flutter SDK.
The initialize
method has the following parameters:
-
client
(required): An instance ofClient
from Appwrite Flutter SDK. -
retryAttempts
(optional): The number of retry attempts to connect to the server. Default is 3. -
pingInterval
(optional): The interval between each retry attempt in milliseconds. Default is 30 seconds. -
pingEnabled
(optional): Whether to enable the ping pong mechanism. Default istrue
. -
autoReconnect
(optional): Whether to automatically reconnect to the server when the connection is lost. Default istrue
. However, theautoReconnect
will be stopped when it reaches theretryAttempts
.
You have to dispose the realtime
object when you don't need it anymore.
realtime.dispose();
According to this site https://tools.ietf.org/html/rfc6455
The WebSocket specification defines ping and pong message opcodes as part of the protocol. These can serve as a way to keep a connection active even if data is not being transmitted. Pings may be sent in either direction. If the client receives a ping, a pong reply will be automatically sent.
However, the Appwrite Websocket does not support two-way communication. So it is expected that the server will send you a message something like this. "{"type":"error","data":{"code":1003,"message":"Message type is not valid."}}
. In this case, the package will automatically reconnect to the server. But the expected must be a pong message from the server. So, the pingInterval
is the interval between each ping message to the server. If the server does not respond with a pong message, the package will automatically reconnect to the server. Hopefully, the Appwrite team will implement the pong message in the future.
The subscribe method is similar to the Appwrite SDK. It subscribes to a channel and listens to the events. However, this time the method is asynchronous.
Future<RealtimeSubscriptionExt> subscribe(String channel) async {
return await realtime.subscribe([channel]);
}
The stateStream
is a Stream
that emits the RealtimeState
of the websocket connection.
realtime.stateStream.listen((state) {
print(state);
});
We have a different state in RealtimeState
enum.
ConnectedState
: The websocket connection is connected.DisconnectedState
: The websocket connection is disconnected.ReconnectingState
: The websocket connection is reconnecting.ErrorState
: The websocket connection is failed to connect.SubscribedState
: The websocket connection is subscribed to a channel.UnsubscribedState
: The websocket connection is unsubscribed from a channel.PingState
: The websocket connection is sending a ping message to the server.DisposingState
: The websocket connection is disposing.
To use that:
realtime.stateStream.listen((state) {
if(state is ErrorState){
showErrorDialog();
}
});
The state
is a getter that returns the current RealtimeState
of the websocket connection.
print(realtime.state);
The getConnectionCompleter
is a Completer
that completes when the websocket connection is connected. It can be used if you are trying to create new document. But you have to check first if the websocket connection is connected.
Future<void> doSomething() async{
isLoading = true;
await realtime.getConnectionCompleter.future;
await createDocument();
}
You can manually reconnect to the server by calling the reconnect
method.
realtime.reconnect();
Whether to enable the ping pong mechanism. Default is true
.
realtime.setPingEnabled(false);
We're always looking for contributions to help improve the Realtime feature in the Appwrite Flutter SDK or if you want to add more features to this package. If you have ideas, bug reports, or enhancements, please feel free to help us by:
- Submitting a Pull Request: If you have a specific improvement or bug fix, submit a pull request with your changes.
- Opening an Issue: For ideas, feedback, or found bugs, open an issue in our GitHub repository.
- Joining the Discussion: Participate in discussions in our GitHub issues or our community chat to help shape the future of Realtime in Appwrite Flutter.
Your contributions are highly appreciated!