2023-07-20 19:38:56 +00:00
|
|
|
import 'dart:convert';
|
|
|
|
|
2023-07-20 21:30:39 +00:00
|
|
|
import 'package:stackwallet/dto/ordinals/inscription_data.dart';
|
2023-07-20 19:38:56 +00:00
|
|
|
import 'package:stackwallet/dto/ordinals/litescribe_response.dart';
|
2023-09-08 21:09:59 +00:00
|
|
|
import 'package:stackwallet/networking/http.dart';
|
|
|
|
import 'package:stackwallet/services/tor_service.dart';
|
|
|
|
import 'package:stackwallet/utilities/prefs.dart';
|
2023-07-20 19:38:56 +00:00
|
|
|
|
|
|
|
class LitescribeAPI {
|
|
|
|
static final LitescribeAPI _instance = LitescribeAPI._internal();
|
|
|
|
|
|
|
|
factory LitescribeAPI({required String baseUrl}) {
|
|
|
|
_instance.baseUrl = baseUrl;
|
|
|
|
return _instance;
|
|
|
|
}
|
|
|
|
|
|
|
|
LitescribeAPI._internal();
|
2023-09-08 21:09:59 +00:00
|
|
|
HTTP client = HTTP();
|
2023-07-20 19:38:56 +00:00
|
|
|
|
|
|
|
late String baseUrl;
|
|
|
|
|
|
|
|
Future<LitescribeResponse> _getResponse(String endpoint) async {
|
2023-09-08 21:09:59 +00:00
|
|
|
final response = await client.get(
|
|
|
|
url: Uri.parse('$baseUrl$endpoint'),
|
2023-09-15 19:51:20 +00:00
|
|
|
proxyInfo: Prefs.instance.useTor
|
|
|
|
? TorService.sharedInstance.getProxyInfo()
|
|
|
|
: null,
|
2023-09-08 21:09:59 +00:00
|
|
|
);
|
|
|
|
if (response.code == 200) {
|
2023-07-20 19:38:56 +00:00
|
|
|
return LitescribeResponse(data: _validateJson(response.body));
|
|
|
|
} else {
|
2023-07-27 19:47:22 +00:00
|
|
|
throw Exception(
|
|
|
|
'LitescribeAPI _getResponse exception: Failed to load data');
|
2023-07-20 19:38:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Map<String, dynamic> _validateJson(String responseBody) {
|
|
|
|
final parsed = jsonDecode(responseBody);
|
|
|
|
if (parsed is Map<String, dynamic>) {
|
|
|
|
return parsed;
|
|
|
|
} else {
|
2023-07-27 19:47:22 +00:00
|
|
|
throw const FormatException(
|
|
|
|
'LitescribeAPI _validateJson exception: Invalid JSON format');
|
2023-07-20 19:38:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-27 19:47:22 +00:00
|
|
|
Future<List<InscriptionData>> getInscriptionsByAddress(String address,
|
|
|
|
{int cursor = 0, int size = 1000}) async {
|
2023-07-20 19:46:15 +00:00
|
|
|
// size param determines how many inscriptions are returned per response
|
|
|
|
// default of 1000 is used to cover most addresses (I assume)
|
|
|
|
// if the total number of inscriptions at the address exceeds the length of the list of inscriptions returned, another call with a higher size is made
|
|
|
|
final int defaultLimit = 1000;
|
2023-07-27 19:47:22 +00:00
|
|
|
final response = await _getResponse(
|
|
|
|
'/address/inscriptions?address=$address&cursor=$cursor&size=$size');
|
2023-07-20 19:46:15 +00:00
|
|
|
|
|
|
|
// Check if the number of returned inscriptions equals the limit
|
|
|
|
final int total = response.data['result']['total'] as int;
|
2023-07-27 20:32:18 +00:00
|
|
|
|
2023-07-27 19:47:16 +00:00
|
|
|
int currentSize = 0;
|
2023-07-27 20:32:18 +00:00
|
|
|
if (total == 0) {
|
|
|
|
return <InscriptionData>[];
|
2023-07-27 19:47:16 +00:00
|
|
|
}
|
2023-07-20 19:46:15 +00:00
|
|
|
|
2023-07-27 20:32:18 +00:00
|
|
|
final list = response.data['result']!['list'];
|
|
|
|
currentSize = list.length as int;
|
|
|
|
|
2023-07-20 19:46:15 +00:00
|
|
|
if (currentSize == size && currentSize < total) {
|
|
|
|
// If the number of returned inscriptions equals the limit and there are more inscriptions available,
|
2023-07-20 19:48:12 +00:00
|
|
|
// increment the cursor and make the next API call to fetch the remaining inscriptions.
|
|
|
|
final int newCursor = cursor + size;
|
|
|
|
return getInscriptionsByAddress(address, cursor: newCursor, size: size);
|
2023-07-20 19:46:15 +00:00
|
|
|
} else {
|
|
|
|
try {
|
2023-07-20 21:49:26 +00:00
|
|
|
// Iterate through the list and create InscriptionData objects from each element
|
|
|
|
final List<InscriptionData> inscriptions = (list as List<dynamic>)
|
2023-07-27 19:47:22 +00:00
|
|
|
.map((json) =>
|
|
|
|
InscriptionData.fromJson(json as Map<String, dynamic>))
|
2023-07-20 21:49:26 +00:00
|
|
|
.toList();
|
|
|
|
|
|
|
|
return inscriptions;
|
2023-07-20 19:46:15 +00:00
|
|
|
} catch (e) {
|
2023-07-27 19:47:22 +00:00
|
|
|
throw const FormatException(
|
|
|
|
'LitescribeAPI getInscriptionsByAddress exception: AddressInscriptionResponse.fromJson failure');
|
2023-07-20 19:46:15 +00:00
|
|
|
}
|
2023-07-20 19:38:56 +00:00
|
|
|
}
|
|
|
|
}
|
2023-07-27 19:47:22 +00:00
|
|
|
}
|