createRoomOnMediaSFU function
- CreateMediaSFUOptions options
createRoomOnMediaSFU
Sends a request to create a new room on MediaSFU. This function validates
the provided credentials and dynamically determines the endpoint based on
the localLink. It performs an HTTP POST request with the given payload
and returns the response or an error. Includes rate limiting to prevent
duplicate requests within a 30-second window.
Parameters:
payload(CreateMediaSFURoomOptions): The payload containing room creation details.apiUserName(String): The API username used for authentication.apiKey(String): The API key for authentication (must be exactly 64 characters).localLink(String, optional): A local link for community edition servers. If provided, it replaces the default MediaSFU endpoint.
Returns:
- A
Future<CreateJoinRoomResult>containing:success(bool): Indicates whether the request was successful.data(CreateJoinRoomResponse|CreateJoinRoomError): The response data or error details.
Example Usage:
final payload = CreateMediaSFURoomOptions(
action: 'create',
duration: 60,
capacity: 10,
userName: 'hostUser',
);
final result = await createRoomOnMediaSFU(
CreateMediaSFUOptions(
payload: payload,
apiUserName: "apiUser123",
apiKey: "1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
localLink: "https://custom.localserver.com",
);
);
if (result.success) {
print('Room created successfully: ${result.data}');
} else {
print('Failed to create room: ${result.data.error}');
}
Implementation
Future<CreateJoinRoomResult> createRoomOnMediaSFU(
CreateMediaSFUOptions options,
) async {
try {
// Extract options
final payload = options.payload;
String apiUserName = options.apiUserName;
String apiKey = options.apiKey;
String localLink = options.localLink;
// Build a unique identifier for this create request
final String roomIdentifier =
'create_${payload.userName}_${payload.duration}_${payload.capacity}';
final String pendingKey = 'mediasfu_pending_$roomIdentifier';
const int pendingTimeout = 30 * 1000; // 30 seconds in milliseconds
// Check pending status to prevent duplicate requests
try {
final SharedPreferences prefs = await SharedPreferences.getInstance();
final String? pendingRequest = prefs.getString(pendingKey);
if (pendingRequest != null) {
final Map<String, dynamic> pendingData = jsonDecode(pendingRequest);
final int timeSincePending = DateTime.now().millisecondsSinceEpoch -
((pendingData['timestamp'] as num?)?.toInt() ?? 0);
if (timeSincePending < pendingTimeout) {
return CreateJoinRoomResult(
data:
CreateJoinRoomError(error: 'Room creation already in progress'),
success: false,
);
} else {
// Stale lock, clear it
await prefs.remove(pendingKey);
}
}
} catch (e) {
// Ignore SharedPreferences read/JSON errors
}
// Validate credentials
if (apiUserName.isEmpty ||
apiKey.isEmpty ||
apiUserName == "yourAPIUSERNAME" ||
apiKey == "yourAPIKEY" ||
apiKey.length != 64 ||
apiUserName.length < 6) {
return CreateJoinRoomResult(
data: CreateJoinRoomError(error: "Invalid credentials"),
success: false,
);
}
// Choose the appropriate endpoint
String endpoint = 'https://mediasfu.com/v1/rooms';
if (localLink.isNotEmpty &&
!localLink.contains('mediasfu.com') &&
localLink.length > 1) {
localLink = localLink.replaceAll(RegExp(r'/$'), '');
endpoint = '$localLink/createRoom';
}
// Mark request as pending
try {
final SharedPreferences prefs = await SharedPreferences.getInstance();
final Map<String, dynamic> pendingData = {
'timestamp': DateTime.now().millisecondsSinceEpoch,
'payload': {
'action': 'create',
'userName': payload.userName,
'duration': payload.duration,
'capacity': payload.capacity,
},
};
await prefs.setString(pendingKey, jsonEncode(pendingData));
// Auto-clear the pending flag after timeout to avoid stale locks
Future.delayed(Duration(milliseconds: pendingTimeout), () async {
try {
final SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.remove(pendingKey);
} catch (e) {
// Ignore errors
}
});
} catch (e) {
// Ignore SharedPreferences write errors
}
Map<String, dynamic> payloadJson = payload.toMap();
// Prepare the request
final response = await http.post(
Uri.parse(endpoint),
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer $apiUserName:$apiKey",
},
body: jsonEncode(payloadJson),
);
// Handle response
if (response.statusCode == 200 || response.statusCode == 201) {
final data = jsonDecode(response.body);
// Clear pending status on success
try {
final SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.remove(pendingKey);
} catch (e) {
// Ignore errors
}
return CreateJoinRoomResult(
data: CreateJoinRoomResponse.fromJson(data),
success: true,
);
} else {
final errorData = jsonDecode(response.body);
// Clear pending status on error
try {
final SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.remove(pendingKey);
} catch (e) {
// Ignore errors
}
return CreateJoinRoomResult(
data: CreateJoinRoomError.fromJson(errorData),
success: false,
);
}
} catch (error) {
// Clear pending status on error
try {
final SharedPreferences prefs = await SharedPreferences.getInstance();
final String roomIdentifier =
'create_${options.payload.userName}_${options.payload.duration}_${options.payload.capacity}';
await prefs.remove('mediasfu_pending_$roomIdentifier');
} catch (e) {
// Ignore errors
}
// Handle unexpected errors
return CreateJoinRoomResult(
data: CreateJoinRoomError(
error: 'Unable to create room, ${error.toString()}'),
success: false,
);
}
}