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,
);
}
}