-
Notifications
You must be signed in to change notification settings - Fork 19
feat: Replace Pinata IPFS with Web3.Storage (free alternative) #27
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
feat: Replace Pinata IPFS with Web3.Storage (free alternative) #27
Conversation
Fixes StabilityNexus#25 - Find an alternative to IPFS ## Changes: - Added new StorageService with Web3.Storage as primary provider - Web3.Storage offers 5GB free storage with no cost restrictions - Maintains backward compatibility with existing Pinata setup - Falls back to Pinata if Web3.Storage is not configured - Added multi-gateway fallback for image loading reliability - Updated all files using IPFS upload functionality ## New Environment Variable: - WEB3_STORAGE_TOKEN: Get free at https://web3.storage ## Benefits: - Free 5GB storage (vs Pinata's limited free tier) - Same IPFS hash format (content-addressable) - Backed by Filecoin for persistence - Multiple gateway fallbacks for reliability
WalkthroughThe PR replaces Pinata-only IPFS uploads with a new multi-provider storage service that prioritizes Web3.Storage (free pinning) with Pinata as a fallback. Imports across the codebase are migrated, and gateway fallback logic in image widgets is enhanced to support multiple alternative IPFS gateways. Changes
Sequence DiagramsequenceDiagram
participant UI as UI Layer
participant SS as StorageService
participant W3S as Web3.Storage API
participant PIN as Pinata API
participant IPFS as IPFS Gateways
UI->>SS: uploadFile(file, setUploadingState)
activate SS
SS->>SS: setUploadingState(true)
rect rgb(76, 175, 80, 0.1)
note over SS,W3S: Primary: Web3.Storage
SS->>W3S: POST /upload (multipart)
alt Web3.Storage Success
W3S-->>SS: w3s.link gateway URL
SS->>IPFS: return gateway URL
else Web3.Storage Fails
W3S-->>SS: error
rect rgb(255, 193, 7, 0.1)
note over SS,PIN: Fallback: Pinata
SS->>PIN: POST /pinning/pinFileToIPFS
alt Pinata Success
PIN-->>SS: gateway URL
SS->>IPFS: return gateway URL
else Pinata Fails
PIN-->>SS: error
SS->>SS: log error
SS-->>UI: null
end
end
end
end
SS->>SS: setUploadingState(false)
SS-->>UI: gateway URL or null
deactivate SS
UI->>SS: getAlternativeGateways(originalUrl)
activate SS
SS->>SS: extractCidFromUrl(url)
SS-->>UI: List[alternative gateway URLs]
deactivate SS
Estimated Code Review Effort🎯 3 (Moderate) | ⏱️ ~20 minutes
Poem
Pre-merge checks and finishing touches✅ Passed checks (5 passed)
✨ Finishing touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
tean name bigbull |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (2)
lib/widgets/profile_widgets/user_profile_viewer_widget.dart (1)
168-186: Gateway fallback only tries one alternative.The fallback logic uses
alternatives[1](ipfs.io) but doesn't attempt the remaining gateways (Cloudflare, dweb.link) if that also fails. Consider iterating through more alternatives for improved reliability, or accept this as a reasonable tradeoff to avoid deeply nested error handlers.A more comprehensive fallback could use a recursive or loop-based approach:
Widget _buildImageWithFallback(String originalUrl, int gatewayIndex) { final alternatives = StorageService.getAlternativeGateways(originalUrl); if (gatewayIndex >= alternatives.length) { return Icon(Icons.person, size: 40, color: getThemeColors(context)['textSecondary']); } return Image.network( alternatives[gatewayIndex], fit: BoxFit.cover, errorBuilder: (context, error, stackTrace) { return _buildImageWithFallback(originalUrl, gatewayIndex + 1); }, ); }lib/utils/services/storage_service.dart (1)
68-98: Consider adding HTTP request timeouts.The HTTP requests to Web3.Storage (and Pinata) don't specify timeouts. On slow or unresponsive networks, this could cause the upload to hang indefinitely, blocking the UI.
static Future<String?> _uploadToWeb3Storage(File file) async { try { final url = Uri.parse('https://api.web3.storage/upload'); final request = http.MultipartRequest('POST', url); request.headers.addAll({ 'Authorization': 'Bearer $_web3StorageToken', }); request.files.add( await http.MultipartFile.fromPath('file', file.path), ); - final streamedResponse = await request.send(); + final streamedResponse = await request.send().timeout( + const Duration(minutes: 2), + onTimeout: () { + throw TimeoutException('Web3.Storage upload timed out'); + }, + ); final response = await http.Response.fromStream(streamedResponse);
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
.env.stencil(1 hunks)lib/pages/mint_nft/mint_nft_images.dart(1 hunks)lib/pages/organisations_pages/create_organisation.dart(1 hunks)lib/pages/register_user_page.dart(1 hunks)lib/pages/tree_details_page.dart(1 hunks)lib/utils/services/ipfs_services.dart(0 hunks)lib/utils/services/storage_service.dart(1 hunks)lib/widgets/profile_widgets/profile_section_widget.dart(2 hunks)lib/widgets/profile_widgets/user_profile_viewer_widget.dart(2 hunks)
💤 Files with no reviewable changes (1)
- lib/utils/services/ipfs_services.dart
🔇 Additional comments (12)
.env.stencil (1)
3-9: Well-documented environment configuration.The new
WEB3_STORAGE_TOKENvariable is properly documented with helpful comments indicating where to obtain the token and the benefits (5GB free). The distinction between the recommended provider (Web3.Storage) and legacy fallback (Pinata) is clear.lib/pages/register_user_page.dart (1)
10-10: Import migration looks correct.The import change to
storage_service.dartis appropriate. TheuploadToIPFSfunction continues to work via the backward-compatible wrapper in the new service.lib/pages/tree_details_page.dart (1)
11-11: Import migration is correct.The import change aligns with the new storage service architecture while maintaining backward compatibility through the
uploadToIPFSwrapper function.lib/pages/mint_nft/mint_nft_images.dart (1)
10-10: Import updated correctly.The migration to
storage_service.dartmaintains the existing upload flow for multiple NFT images.lib/pages/organisations_pages/create_organisation.dart (1)
9-9: Import migration completed.The storage service import correctly replaces the legacy IPFS service for organisation logo uploads.
lib/widgets/profile_widgets/user_profile_viewer_widget.dart (1)
9-9: Import added for gateway fallback support.The storage service import enables the new multi-gateway fallback functionality.
lib/widgets/profile_widgets/profile_section_widget.dart (2)
10-10: Storage service import added.Enables the gateway fallback functionality for profile photo loading.
391-415: Consistent gateway fallback implementation.The fallback pattern matches
user_profile_viewer_widget.dart, maintaining consistency across the codebase. The same single-alternative limitation applies here.lib/utils/services/storage_service.dart (4)
1-15: Well-structured storage service with clear documentation.The service design with Web3.Storage as the primary free provider and Pinata as fallback aligns well with the PR objectives. The class documentation clearly explains the benefits of Web3.Storage.
145-157: Good selection of fallback gateways.The gateway list provides solid redundancy with well-known, reliable IPFS gateways. The w3s.link gateway (Web3.Storage's own) is appropriately placed first for best performance with Web3.Storage uploads.
160-167: Clean backward compatibility wrapper.The
uploadToIPFSfunction maintains API compatibility with existing code, making the migration seamless across the codebase.
133-143: CID regex suggestion is factually incorrect.The regex
[a-zA-Z0-9]+is overly permissive (includes0,O,I,lwhich are invalid in Base58), but it will match all valid CIDs in practice since real CIDv0 and CIDv1 identifiers contain only a subset of alphanumeric characters.The suggested improvement—adding underscore and hyphen
[a-zA-Z0-9_-]—is wrong. Neither underscore nor hyphen appear in IPFS CID specifications: CIDv0 uses Base58 (alphabet:123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz), and CIDv1 typically uses RFC-4648 Base32 (alphabet:a-z2-7). Neither includes_or-. The current regex, while not ideally strict, is functionally sufficient and the suggested modification would introduce invalid characters.
Fixes #25 -
Changes:
New Environment Variable:
Benefits:
Summary by CodeRabbit
New Features
Chores
✏️ Tip: You can customize this high-level summary in your review settings.