-
Notifications
You must be signed in to change notification settings - Fork 15
/
Copy pathNFTStorageClient.cs
363 lines (320 loc) · 13.3 KB
/
NFTStorageClient.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
using UnityEngine;
using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Web;
using System.Text;
using NFTStorage.JSONSerialization;
using UnityEngine.Networking;
namespace NFTStorage.JSONSerialization
{
[Serializable]
public class NFTStorageError
{
public string name;
public string message;
}
[Serializable]
public class NFTStorageFiles
{
public string name;
public string type;
}
[Serializable]
public class NFTStorageDeal
{
public string batchRootCid;
public string lastChange;
public string miner;
public string network;
public string pieceCid;
public string status;
public string statusText;
public int chainDealID;
public string dealActivation;
public string dealExpiration;
}
[Serializable]
public class NFTStoragePin
{
public string cid;
public string name;
public string status;
public string created;
public int size;
// TODO: add metadata parsing ('meta' property)
}
[Serializable]
public class NFTStorageNFTObject
{
public string cid;
public int size;
public string created;
public string type;
public string scope;
public NFTStoragePin pin;
public NFTStorageFiles[] files;
public NFTStorageDeal[] deals;
}
[Serializable]
public class NFTStorageCheckValue
{
public string cid;
public NFTStoragePin pin;
public NFTStorageDeal[] deals;
}
[Serializable]
public class NFTStorageGetFileResponse
{
public bool ok;
public NFTStorageNFTObject value;
public NFTStorageError error;
}
[Serializable]
public class NFTStorageCheckResponse
{
public bool ok;
public NFTStorageCheckValue value;
public NFTStorageError error;
}
[Serializable]
public class NFTStorageListFilesResponse
{
public bool ok;
public NFTStorageNFTObject[] value;
public NFTStorageError error;
}
[Serializable]
public class NFTStorageUploadResponse
{
public bool ok;
public NFTStorageNFTObject value;
public NFTStorageError error;
}
[Serializable]
public class NFTStorageDeleteResponse
{
public bool ok;
}
}
namespace NFTStorage
{
// This is the main class for communicating with nft.storage and IPFS
public class NFTStorageClient : MonoBehaviour
{
// nft.storage API endpoint
private static readonly string nftStorageApiUrl = "https://api.nft.storage/";
// HTTP client to communicate with nft.storage
private static readonly HttpClient nftClient = new HttpClient();
// http client to communicate with IPFS API
private static readonly HttpClient ipfsClient = new HttpClient();
// nft.storage API key
public string apiToken;
/**
<summary>"Start" is called before the first frame update for initializing "NFTStorageClient"</summary>
*/
void Start()
{
nftClient.DefaultRequestHeaders.Add("Accept", "application/json");
if (apiToken != null)
{
nftClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + apiToken);
}
else
{
// log in console in case no API key is found during initialization
Debug.Log("Starting NFT Storage Client without API key, please call 'SetApiToken' method before using class methods.");
}
}
/**
<summary>Auxiliar function for making a HTTP/HTTPS request</summary>
<param name="method">The HTTP method to be used for the request (e.g. GET, POST, DELETE)</param>
<param name="uri">The full URI for the request (including paths and query string parameters)</param>
<param name="requestClient">The client to be used for the request (e.g. nft.storage, IPFS)</param>
<returns>A "Task" which result is a string, containing the raw response data</returns>
*/
private async Task<string> SendHttpRequest(HttpMethod method, string uri, HttpClient requestClient = null)
{
try
{
if (requestClient == null)
{
requestClient = nftClient;
}
HttpRequestMessage request = new HttpRequestMessage(method, uri);
HttpResponseMessage response = await requestClient.SendAsync(request);
response.EnsureSuccessStatusCode();
string responseBody = await response.Content.ReadAsStringAsync();
return responseBody;
}
catch (HttpRequestException e)
{
Debug.Log("HTTP Request Exception: " + e.Message);
return null;
}
}
/**
<summary>Auxiliar function for uploading a file via HTTP request</summary>
<param name="uri">The HTTP API endpoint</param>
<param name="paramString">The data to be uploaded, formatted as a string</param>
<returns>A "Task" which result is a string, containing the raw response data</returns>
*/
private async Task<string> Upload(string uri, string pathFile)
{
byte[] bytes = System.IO.File.ReadAllBytes(pathFile);
try
{
using (var content = new ByteArrayContent(bytes))
{
content.Headers.ContentType = new MediaTypeHeaderValue("*/*");
nftClient.Timeout = new TimeSpan(1, 0, 0);// 1 hour should be enough probably
//Send it
print("Uploading...");
var response = await nftClient.PostAsync(uri, content);
response.EnsureSuccessStatusCode();
Stream responseStream = await response.Content.ReadAsStreamAsync();
StreamReader reader = new StreamReader(responseStream);
return reader.ReadToEnd();
}
}
catch (HttpRequestException e)
{
Debug.Log("HTTP Request Exception: " + e.Message);
return null;
}
}
UnityWebRequest uwr;
IEnumerator PostRequest(string url, string filePath)
{
byte[] dataToPost = System.IO.File.ReadAllBytes(filePath);
UploadHandlerRaw uhr = new UploadHandlerRaw(dataToPost);
uwr = new UnityWebRequest(url, "POST", new DownloadHandlerBuffer(), uhr);
uwr.SetRequestHeader("Accept", "application/json");
uwr.SetRequestHeader("Authorization", "Bearer " + apiToken);
uwr.SetRequestHeader("Content-Type", "*/*");
yield return uwr.SendWebRequest();
if (uwr.isNetworkError)
{
Debug.Log("Error While Sending: " + uwr.error);
}
else
{
Debug.Log("Received: " + uwr.downloadHandler.text);
}
}
IEnumerator UploadProgressCoroutine()
{
while (!uwr.isDone)
{
HandleProgress(uwr.uploadProgress);
yield return null;
}
}
void HandleProgress(float currentProgress)
{
print(currentProgress); // upload progrees bettween 0 and 1
}
/**
<summary>Set API token to be used as authorization header for "nft.storage" HTTP API requests</summary>
<param name="token">A valid API key to be used with "nft.storage" API</param>
*/
public void SetApiToken(string token)
{
apiToken = token;
if (nftClient.DefaultRequestHeaders.Contains("Authorization"))
{
nftClient.DefaultRequestHeaders.Remove("Authorization");
}
nftClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + apiToken);
}
/**
<summary>Retrieve details of files that were previously uploaded using "nft.storage" HTTP API</summary>
<param name="before">An ISO 8601 date/time string, which is used to filter solely files stored previously to this date/time</param>
<param name="limit">An integer indicating the maximum number of files that should be retrieved</param>
<returns>A "Task" which result is a "NFTStorageListFilesResponse" object, obtained by parsing JSON from "nft.storage" API response (GET / endpoint)</returns>
*/
public async Task<NFTStorageListFilesResponse> ListFiles(string before = null, int limit = 10)
{
var query = HttpUtility.ParseQueryString(string.Empty);
if (before != null) query["before"] = before;
query["limit"] = limit.ToString();
string queryString = query.ToString();
string requestUri = nftStorageApiUrl + "?" + queryString;
string rawResponse = await SendHttpRequest(HttpMethod.Get, requestUri);
NFTStorageListFilesResponse parsedResponse = JsonUtility.FromJson<NFTStorageListFilesResponse>(rawResponse);
return parsedResponse;
}
/**
<summary>Get details of a previously uploaded file using "nft.storage" HTTP API</summary>
<param name="cid">The alphanumeric hash (base32) which uniquely identifies the file stored in IPFS system</param>
<returns>A "Task" which result is a "NFTStorageGetFileResponse" object, obtained by parsing JSON from "nft.storage" API response (GET /[cid] endpoint)</returns>
*/
public async Task<NFTStorageGetFileResponse> GetFile(string cid)
{
string requestUri = nftStorageApiUrl + "/" + cid;
string rawResponse = await SendHttpRequest(HttpMethod.Get, requestUri);
NFTStorageGetFileResponse parsedResponse = JsonUtility.FromJson<NFTStorageGetFileResponse>(rawResponse);
return parsedResponse;
}
/**
<summary>Download data for specific file stored via "nft.storage" (using IPFS)</summary>
<param name="cid">The alphanumeric hash (base32) which uniquely identifies the file stored in IPFS system</param>
<returns>A string containing all data from the file, in its raw format</returns>
*/
public async Task<string> GetFileData(string cid)
{
string requestUri = "https://" + cid + ".ipfs.dweb.link/";
string response = await SendHttpRequest(HttpMethod.Get, requestUri, ipfsClient);
return response;
}
/**
<summary>Check a previously uploaded file using "nft.storage" HTTP API</summary>
<param name="cid">The alphanumeric hash (base32) which uniquely identifies the file stored in IPFS system</param>
<returns>A "Task" which result is a "NFTStorageCheckResponse" object, obtained by parsing JSON from "nft.storage" API response (GET /check endpoint)</returns>
*/
public async Task<NFTStorageCheckResponse> CheckFile(string cid)
{
string requestUri = nftStorageApiUrl + "/check/" + cid;
string rawResponse = await SendHttpRequest(HttpMethod.Get, requestUri);
NFTStorageCheckResponse parsedResponse = JsonUtility.FromJson<NFTStorageCheckResponse>(rawResponse);
return parsedResponse;
}
/**
<summary>Delete a previously uploaded file using "nft.storage" HTTP API</summary>
<param name="cid">The alphanumeric hash (base32) which uniquely identifies the file stored in IPFS system</param>
<returns>A "Task" which result is a "NFTStorageDeleteResponse" object, obtained by parsing JSON from "nft.storage" API response (DELETE / endpoint)</returns>
*/
public async Task<NFTStorageDeleteResponse> DeleteFile(string cid)
{
string requestUri = nftStorageApiUrl + "/" + cid;
string rawResponse = await SendHttpRequest(HttpMethod.Delete, requestUri);
NFTStorageDeleteResponse parsedResponse = JsonUtility.FromJson<NFTStorageDeleteResponse>(rawResponse);
return parsedResponse;
}
/**
<summary>Upload a file using "nft.storage" HTTP API</summary>
<returns>A "Task" which result is a "NFTStorageUploadResponse" object, obtained by parsing JSON from "nft.storage" API response (POST /upload endpoint)</returns>
*/
public async Task<NFTStorageUploadResponse> UploadDataFromStringHttpClient(string path)
{
string requestUri = nftStorageApiUrl + "/upload";
string rawResponse = await Upload(requestUri, path);
NFTStorageUploadResponse parsedResponse = JsonUtility.FromJson<NFTStorageUploadResponse>(rawResponse);
return parsedResponse;
}
/*
<summary>Upload a file using "nft.storage" unitywebrequest </summary>
*/
public void UploadDataFromStringUnityWebrequest(string path)
{
string requestUri = nftStorageApiUrl + "/upload";
uwr = null;
StartCoroutine(PostRequest(requestUri, path));
StartCoroutine(UploadProgressCoroutine());
}
}
}