A Dart package providing a wrapper around the RetroShare JSON-RPC API, enabling interaction with a running RetroShare node from Dart and Flutter applications.
- Authentication: Log in, manage API tokens.
- Identity Management: Create/get identities, manage contacts.
- Peer Management: Add friends, handle invites, get connection status, discover peers.
- Messaging: Send/receive private messages, manage chat lobbies.
- GXS Services: Interact with Channels, Forums, and Circles.
- File Sharing: Manage downloads, shared directories, file links.
- Event Handling: Subscribe to real-time RetroShare events using Server-Sent Events (via the standard
httppackage). - Configuration: Get/set RetroShare settings like data rates.
- Utilities: Helper functions for common tasks like checking service status and retrieving combined identity information.
- A running RetroShare node instance.
- The JSON API must be enabled in your RetroShare node (usually accessible at
http://127.0.0.1:9092by default).
Add the package to your pubspec.yaml:
dependencies:
retroshare_api_wrapper: ^0.1.0 # Or the latest versionOr install using the command line:
flutter pub add retroshare_api_wrapperThen, import the package in your Dart code:
import 'package:retroshare_api_wrapper/retroshare.dart';
import 'package:retroshare_api_wrapper/src/rs_models.dart'; // For data models like AuthToken, Location etc.Most API calls require an AuthToken which encapsulates the necessary authentication credentials (username/password or API key/value).
import 'package:retroshare_api_wrapper/retroshare.dart';
import 'package:retroshare_api_wrapper/src/rs_models.dart'; // For data models like AuthToken, Location etc.
// --- Authentication Example (Login Helper) ---
Future<AuthToken?> login(String username, String password) async {
try {
// Assuming getLocations provides necessary details including locationId
var locations = await RsLoginHelper.getLocations();
if (locations.isNotEmpty) {
// Find the correct location object based on username if multiple exist
var selectedAccount = locations.firstWhere((loc) => loc['name'] == username, orElse: () => null);
if (selectedAccount != null) {
bool loginSuccess = await RsLoginHelper.requestLogIn(selectedAccount, password);
if (loginSuccess) {
// Use username/password directly for AuthToken in this wrapper
return AuthToken(username, password);
}
}
}
} catch (e) {
print("Login failed: $e");
}
return null;
}
// --- Example API Call (Get Friend List) ---
Future<void> printFriendList(AuthToken authToken) async {
if (authToken == null) {
print("Not authenticated.");
return;
}
try {
List<String> friendIds = await RsPeers.getFriendList(authToken);
print("Friend SSL IDs: $friendIds");
// You can then get details for each friend
for (String sslId in friendIds) {
Location friendDetails = await RsPeers.getPeerDetails(sslId, authToken);
print(" - ${friendDetails.name} (${friendDetails.location})");
}
} catch (e) {
print("Error getting friend list: $e");
}
}
// --- Example Event Handling (Chat Messages) ---
StreamSubscription<String>? chatSubscription;
void listenToChatMessages(AuthToken authToken) {
if (authToken == null) {
print("Not authenticated.");
return;
}
// Use the utility function for easier chat message handling
eventsRegisterChatMessage(
authToken: authToken,
listenCb: (dynamic eventJson, ChatMessage? chatMessage) {
if (chatMessage != null) {
print("Received Chat: ${chatMessage.mMsg}");
// Handle the incoming chat message in your application UI/logic
} else {
print("Received non-chat message event or parsing error: $eventJson");
}
},
onError: (error, stacktrace) {
print("Error listening to chat events: $error");
// Handle subscription errors (e.g., attempt to reconnect)
},
).then((subscriptionFuture) {
subscriptionFuture?.then((subscription) {
chatSubscription = subscription;
print("Subscribed to chat events.");
});
});
}
void stopListeningToChat() {
chatSubscription?.cancel();
print("Unsubscribed from chat events.");
}
// --- Main Example Usage ---
void main() async {
// IMPORTANT: Replace with your actual Retroshare node credentials
String username = "your_retroshare_user";
String password = "your_retroshare_password";
// Attempt to login
AuthToken? token = await login(username, password);
if (token != null) {
print("Login successful!");
await printFriendList(token);
listenToChatMessages(token);
// Keep the application running to receive events or perform other actions
// In a real app, this would be part of your Flutter UI lifecycle
// await Future.delayed(Duration(minutes: 5));
// stopListeningToChat();
} else {
print("Authentication failed.");
}
}The wrapper organizes RetroShare API calls into static classes, generally mirroring the API structure:
RsAccounts,RsLoginHelper,RsIdentity: User accounts, login, identity management.RsPeers: Friend management, connections, invites.RsMsgs: Private messaging, chat lobbies.RsGxsChannel,RsGxsForum,RsGxsCircles: GXS services.RsFiles: File transfer management.RsConfig: Node configuration.RsEvents: Real-time event subscriptions.RsJsonApi: General API utilities (version, token management).- Various utility functions are also provided at the top level.
Check the source code in lib/src/retroshare.dart for available methods and their parameters.
API calls return Futures. Network errors (like SocketException if the RetroShare node is down) or API-level errors (invalid parameters, authentication failure, etc.) typically result in thrown Exceptions. Use try-catch blocks to handle potential failures gracefully.
The package includes a suite of unit tests to verify the functionality of the API wrapper. To run the tests, use the standard Flutter test command from the root directory of the package:
flutter testThis will execute the tests defined in the test/ directory.
Contributions are welcome! Please feel free to submit pull requests or open issues.