This article shows how to create a BOT with real-time data using the Dart language and Bluesky's Firehose API.
From the Firehose API, you can retrieve Bluesky events that occur on a particular server in real time, allowing you to develop very interactive BOTs. For example, a reply can be returned in real time to data that has been mentions to a specific account.
After reading this article you will surely be able to create a BOT using the Firehose API.
BOTs intended to spam will be subject to account suspension.
I will not be liable for any account suspension as a result of spamming or otherwise. Please execute with care when testing.
Using Package
To easily handle the Bluesky API in Dart/Flutter, use the following package.
myConsciousness / atproto.dart
π¦ AT Protocol and Bluesky things for Dart and Flutter.
AT Protocol and Bluesky Social Things for Dart/Flutter π¦
- 1. Motivation πͺ
- 2. Packages & Tools βοΈ
- 3. Developer Quickstart ποΈ
- 4. Who is using atproto.dart? π
- 5. Contribution π
- 6. Contributors β¨
- 7. Support β€οΈ
- 8. License π
- 9. More Information π§
Welcome to atproto.dart π¦
This project will maximize your development productivity about AT Protocol and Bluesky things.
Give a β on GitHub repository and follow shinyakato.dev on Bluesky!
1. Motivation πͺ
AT Protocol and Bluesky are awesome.
This wonderful platform needs a standard and highly integrated SDK atproto.dart provides the best development experience in such matters for Dart/Flutter devs.
2. Packages & Tools βοΈ
2.1. Dart Packages
Package | pub.dev | Docs |
---|---|---|
at_identifier: core library for the syntax in the AT Protocol standard | README | |
nsid: |
If you want to learn more about bluesky package, see following official website.
Install
Let's install bluesky with the following commands.
dart pub add bluesky
dart pub get
Import
Basically, when you use features of the bluesky package, just add the following import.
import 'package:bluesky/bluesky.dart';
Basic
Let's begin with the most basic implementation for using the Firehose API with bluesky package. You can implement it as follows.
import 'package:bluesky/bluesky.dart' as bsky;
Future<void> main() async {
final bluesky = bsky.Bluesky.anonymous();
final subscription = await bluesky.sync.subscribeRepoUpdates();
await for (final event in subscription.data.stream.handleError(print)) {
print(event);
}
}
To start with the most basic point, almost all events (likes and postings and etc) that occur on a particular server in Bluesky are public data. In other words, the Firehose API does not require user authentication.
With the above code, Bluesky's Firehose works perfectly, but user authentication is always required with a specific account to develop a BOT like the one we will cover in this article. This is because the BOT must be logged in with a specific account in order to respond with a reply or other action when a specific event is detected.
So, we need following implementations.
import 'package:bluesky/bluesky.dart' as bsky;
Future<void> main() async {
// This session is active for 120 minutes.
final session = await bsky.createSession(
identifier: 'username or email',
password: 'password',
);
// Refreshed session is active for 90 days.
final refreshedSession = await bsky.refreshSession(
refreshJwt: session.data.refreshJwt,
);
// Create an instance from authenticated session.
final bluesky = bsky.Bluesky.fromSession(refreshedSession.data);
final subscription = await bluesky.sync.subscribeRepoUpdates();
await for (final event in subscription.data.stream.handleError(print)) {
print(event);
}
}
Comparing with the previous code, you will notice that the .createSession
function adds a process to authenticate the user. By passing username and password credentials to the .createSession
function, a Bluesky session is created and you are logged in with a specific account.
But it's important to note, however, that sessions created with the .createSession
function are only valid for 120 minutes. This is a somewhat unreliable time limit when using the Firehose API for long-time connections.
So, let's use the .refreshSession
function. By passing refreshJwt
in the session object created by the .createSession
function as an argument, you can issue a session that is valid for 90 days.
Advanced
Move on to the main issue!
Let's create a BOT that replies with Hello!
if it detects a post "Say hello @test.shinyakato.dev".
import 'package:bluesky/bluesky.dart' as bsky;
Future<void> main() async {
// This session is active for 120 minutes.
final session = await bsky.createSession(
identifier: 'username or email',
password: 'password',
);
// Refreshed session is active for 90 days.
final refreshedSession = await bsky.refreshSession(
refreshJwt: session.data.refreshJwt,
);
// Create an instance from authenticated session.
final bluesky = bsky.Bluesky.fromSession(refreshedSession.data);
final subscription = await bluesky.sync.subscribeRepoUpdates();
// This is a very useful adaptor.
// You can filter only specific events from Firehose.
final adaptor = bsky.RepoCommitAdaptor(
// Triggered only when post is created.
onCreatePost: (data) async {
if (data.record.text.contains('Say hello @test.shinyakato.dev')) {
// Post a reply
await bluesky.feeds.createPost(
text: 'Hello!',
// Reply setting
reply: bsky.ReplyRef(
root: data.toStrongRef(),
parent: data.toStrongRef(),
),
);
print('said hello to ${data.author}!');
}
},
);
await for (final event in subscription.data.stream.handleError(print)) {
switch (event) {
// Firehose events are union type.
// Use `USubscribedRepoCommit` to filter only commit events.
case bsky.USubscribedRepoCommit():
// Execute adaptor like this.
await adaptor.execute(event.data);
}
}
}
Well done, if you run this code and post "Say hello @test.shinyakato.dev", you will instantly receive a reply saying "Hello!".
"Oh no, this seems very difficult to implement!"
Don't worry. The implementation has increased but it's very simple.
First, I describe the RepoCommitAdaptor
class. The RepoCommitAdaptor
class is a solution that allows troublesome commit data records to be filtered and treated as a specific type.
The commit data returned from Firehose contains almost all the record data generated by Bluesky. This means that the implementer must check as to whether the content of the record is a post or a like and so on. But, this is a fairly burdensome task for implementors using Firehose... Well, let RepoCommitAdaptor
take care of all that tedious work.
When using RepoCommitAdaptor
, you can define processing directly in callbacks for specific events such as onCreatePost
as follows.
// This is a very useful adaptor.
// You can filter only specific events from Firehose.
final adaptor = bsky.RepoCommitAdaptor(
// Triggered only when post is created.
onCreatePost: (data) {
// Do something for post data.
},
);
In other words, this callback is executed only for events for which a post was created upon receipt of the Firehose results.
The code for Firehose is then as follows.
await for (final event in subscription.data.stream.handleError(print)) {
switch (event) {
// Firehose events are union type.
// Use `USubscribedRepoCommit` to filter only commit events.
case bsky.USubscribedRepoCommit():
// Execute adaptor like this.
await adaptor.execute(event.data);
}
}
As noted in the comments to the above code, the data returned from Firehose is union. But, it can be easily handled using pattern matching in Dart3.
Union type names in bluesky package is always prefixed with U
, so in this case we specify the USubscribedRepoCommit
class in case
, which represents Firehose's repo commit event.
Finally, the RepoCommitAdaptor
defined earlier is executed in a case statement. This will all be easily resolved.
Conclusion
After reading this article you now understand how to use Dart and Bluesky's Firehose to create a realtime oriented BOT. Although we created a very simple BOT in this article, it's possible to create a more serviceable BOT by incorporating more complex rules. Try various things with the bluesky package!
If you are still not sure how to implement it after reading this article, please mention me on Bluesky.
Also, if you found this article useful, please give a star on GitHub repository. This is very helpful to activate the development community for atproto.dart.
myConsciousness / atproto.dart
π¦ AT Protocol and Bluesky things for Dart and Flutter.
AT Protocol and Bluesky Social Things for Dart/Flutter π¦
- 1. Motivation πͺ
- 2. Packages & Tools βοΈ
- 3. Developer Quickstart ποΈ
- 4. Who is using atproto.dart? π
- 5. Contribution π
- 6. Contributors β¨
- 7. Support β€οΈ
- 8. License π
- 9. More Information π§
Welcome to atproto.dart π¦
This project will maximize your development productivity about AT Protocol and Bluesky things.
Give a β on GitHub repository and follow shinyakato.dev on Bluesky!
1. Motivation πͺ
AT Protocol and Bluesky are awesome.
This wonderful platform needs a standard and highly integrated SDK atproto.dart provides the best development experience in such matters for Dart/Flutter devs.
2. Packages & Tools βοΈ
2.1. Dart Packages
Package | pub.dev | Docs |
---|---|---|
at_identifier: core library for the syntax in the AT Protocol standard | README | |
nsid: |
Thank you.
Top comments (0)