├── .circleci
└── config.yml
├── .gitignore
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── io
│ │ └── textile
│ │ └── textileexample
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── io
│ │ │ └── textile
│ │ │ └── textileexample
│ │ │ └── MainActivity.java
│ └── res
│ │ ├── drawable-v24
│ │ └── ic_launcher_foreground.xml
│ │ ├── drawable
│ │ └── ic_launcher_background.xml
│ │ ├── layout
│ │ └── activity_main.xml
│ │ ├── mipmap-anydpi-v26
│ │ ├── ic_launcher.xml
│ │ └── ic_launcher_round.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ └── values
│ │ ├── colors.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── io
│ └── textile
│ └── textileexample
│ └── ExampleUnitTest.java
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── ipfslite
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ ├── assets
│ │ ├── TEST0.JPG
│ │ ├── TEST1.JPG
│ │ ├── TEST2.JPG
│ │ ├── TEST3.JPG
│ │ ├── TEST4.JPG
│ │ ├── TEST5.JPG
│ │ ├── TEST6.JPG
│ │ └── TEST7.JPG
│ └── java
│ │ └── io
│ │ └── textile
│ │ └── ipfslite
│ │ └── PeerTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── io
│ │ │ └── textile
│ │ │ └── ipfslite
│ │ │ └── Peer.java
│ ├── proto
│ │ └── ipfs_lite.proto
│ └── res
│ │ └── values
│ │ └── strings.xml
│ └── test
│ ├── java
│ └── io
│ │ └── textile
│ │ └── ipfslite
│ │ └── ExampleUnitTest.java
│ └── proto
│ └── ipfs_lite.proto
├── manifest.gradle
└── settings.gradle
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | version: 2.1
2 |
3 | jobs:
4 | build:
5 | docker:
6 | - image: circleci/android:api-28-ndk
7 | steps:
8 | - checkout
9 | - restore_cache:
10 | key: jars-{{ checksum "manifest.gradle" }}-{{ checksum "build.gradle" }}-{{ checksum "app/build.gradle" }}-{{ checksum "ipfslite/build.gradle" }}
11 | - run:
12 | name: Download Dependencies
13 | command: ./gradlew androidDependencies
14 | - save_cache:
15 | paths:
16 | - ~/.gradle
17 | key: jars-{{ checksum "manifest.gradle" }}-{{ checksum "build.gradle" }}-{{ checksum "app/build.gradle" }}-{{ checksum "ipfslite/build.gradle" }}
18 | - run:
19 | name: install
20 | command: |
21 | ./gradlew ipfslite:install
22 |
23 | publish:
24 | docker:
25 | - image: circleci/android:api-28-ndk
26 | steps:
27 | - checkout
28 | - restore_cache:
29 | key: jars-{{ checksum "manifest.gradle" }}-{{ checksum "build.gradle" }}-{{ checksum "app/build.gradle" }}-{{ checksum "ipfslite/build.gradle" }}
30 | - run:
31 | name: Download Dependencies
32 | command: ./gradlew androidDependencies
33 | - save_cache:
34 | paths:
35 | - ~/.gradle
36 | key: jars-{{ checksum "manifest.gradle" }}-{{ checksum "build.gradle" }}-{{ checksum "app/build.gradle" }}-{{ checksum "ipfslite/build.gradle" }}
37 | - run:
38 | name: update version
39 | command: |
40 | sed -i.bak "s/0.0.1-dev/${CIRCLE_TAG}/g" manifest.gradle
41 | - run:
42 | name: install
43 | command: |
44 | ./gradlew ipfslite:install
45 | - run:
46 | name: publish
47 | command: |
48 | ./gradlew ipfslite:bintrayUpload
49 | workflows:
50 | android-ipfs-lite:
51 | jobs:
52 | - build
53 | - publish:
54 | filters:
55 | tags:
56 | only: /.*/
57 | branches:
58 | ignore: /.*/
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | *.apk
3 | *.ap_
4 | *.aab
5 |
6 | # Files for the ART/Dalvik VM
7 | *.dex
8 |
9 | # Java class files
10 | *.class
11 |
12 | # Generated files
13 | bin/
14 | gen/
15 | out/
16 |
17 | # Gradle files
18 | .gradle/
19 | build/
20 |
21 | # Local configuration file (sdk path, etc)
22 | local.properties
23 |
24 | # Proguard folder generated by Eclipse
25 | proguard/
26 |
27 | # Log Files
28 | *.log
29 |
30 | # Android Studio Navigation editor temp files
31 | .navigation/
32 |
33 | # Android Studio captures folder
34 | captures/
35 |
36 | # IntelliJ
37 | *.iml
38 | .idea/workspace.xml
39 | .idea/tasks.xml
40 | .idea/gradle.xml
41 | .idea/assetWizardSettings.xml
42 | .idea/dictionaries
43 | .idea/libraries
44 | .idea/caches
45 | # Android Studio 3 in .gitignore file.
46 | .idea/caches/build_file_checksums.ser
47 | .idea/modules.xml
48 |
49 | # Keystore files
50 | # Uncomment the following lines if you do not want to check your keystore files in.
51 | #*.jks
52 | #*.keystore
53 |
54 | # External native build folder generated in Android Studio 2.2 and later
55 | .externalNativeBuild
56 |
57 | # Google Services (e.g. APIs or Firebase)
58 | # google-services.json
59 |
60 | # Freeline
61 | freeline.py
62 | freeline/
63 | freeline_project_description.json
64 |
65 | # fastlane
66 | fastlane/report.xml
67 | fastlane/Preview.html
68 | fastlane/screenshots
69 | fastlane/test_output
70 | fastlane/readme.md
71 |
72 | # Version control
73 | vcs.xml
74 |
75 | # lint
76 | lint/intermediates/
77 | lint/generated/
78 | lint/outputs/
79 | lint/tmp/
80 | # lint/reports/
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | The following is a set of guidelines for contributing to Textile-related projects, which are hosted in the [Textile organization](https://github.com/textileio). These are just guidelines, not rules. Use your best judgment, and
4 | feel free to propose changes to this document in a pull request.
5 |
6 | Note that Textile is an evolving project, so expect things to change over time as the team learns, listens and refines how we work with the community.
7 |
8 | #### Table Of Contents
9 |
10 | [What should I know before I get started?](#what-should-i-know-before-i-get-started)
11 | * [Code of Conduct](#code-of-conduct)
12 |
13 | [How Can I Contribute?](#how-can-i-contribute)
14 | * [Reporting Bugs](#reporting-bugs)
15 | * [Suggesting Enhancements](#suggesting-enhancements)
16 |
17 | [Additional Notes](#additional-notes)
18 |
19 | ## What should I know before I get started?
20 |
21 | ### Code of Conduct
22 |
23 | This project adheres to the Contributor Covenant [code of conduct](./CODE_OF_CONDUCT.md).
24 | By participating, you are expected to uphold this code.
25 | Please report unacceptable behavior to [contact@textile.io](mailto:contact@textile.io).
26 |
27 | ## How Can I Contribute?
28 |
29 | ### Developing locally
30 |
31 | #### How to Setup
32 |
33 | Generally, Textile projects can be initialized with something like:
34 |
35 | **Step 1:** git clone this repo:
36 |
37 | **Step 2:** cd to the cloned repo:
38 |
39 | **Step 3:** Install the Application with `yarn` or `npm i`
40 |
41 | See each indiviual project's `README` for details.
42 |
43 | ### Reporting Bugs
44 |
45 | This section guides you through submitting a bug report for any Textile repo.
46 | Following these guidelines helps maintainers and the community understand your report, reproduce the behavior, and find related reports.
47 |
48 | Before creating bug reports, please check [this list](../../labels/bug) as you might find out that you don't need to create one. When you are creating a bug report, please [include as many details as possible](#how-do-i-submit-a-good-bug-report).
49 |
50 | #### Before Submitting A Bug Report
51 |
52 | **Perform a [cursory search](../../labels/bug)** to see if the problem has already been reported. If it does exist, add a :thumbsup: to the issue to indicate this is also an issue for you, and add a comment to the existing issue if there is extra information you can contribute.
53 |
54 | #### How Do I Submit A (Good) Bug Report?
55 |
56 | Bugs are tracked as [GitHub issues](https://guides.github.com/features/issues/).
57 |
58 | Simply create an issue on the [Textile issue tracker](../../issues).
59 |
60 | The information we are interested in includes:
61 |
62 | - details about your environment - which build, which operating system
63 | - details about reproducing the issue - what steps to take, what happens, how
64 | often it happens
65 | - other relevant information - log files, screenshots, etc.
66 |
67 | ### Suggesting Enhancements
68 |
69 | This section guides you through submitting an enhancement suggestion for this project, including completely new features and minor improvements to existing functionality. Following these guidelines helps maintainers and the community understand your suggestion :pencil: and find related suggestions :mag_right:.
70 |
71 | Before creating enhancement suggestions, please check [this list](../..//labels/bug)
72 | as you might find out that you don't need to create one. When you are creating
73 | an enhancement suggestion, please [include as many details as possible](#how-do-i-submit-a-good-enhancement-suggestion). Include the steps
74 | that you imagine you would take if the feature you're requesting existed.
75 |
76 | #### Before Submitting An Enhancement Suggestion
77 |
78 | **Perform a [cursory search](../../labels/enhancement)**
79 | to see if the enhancement has already been suggested. If it has, add a
80 | :thumbsup: to indicate your interest in it, or comment if there is additional
81 | information you would like to add.
82 |
83 | #### How Do I Submit A (Good) Enhancement Suggestion?
84 |
85 | Enhancement suggestions are tracked as [GitHub issues](https://guides.github.com/features/issues/).
86 |
87 | Simply create an issue on the [Textile issue tracker](../..//issues)
88 | and provide the following information:
89 |
90 | * **Use a clear and descriptive title** for the issue to identify the
91 | suggestion.
92 | * **Provide a step-by-step description of the suggested enhancement** in as
93 | much detail as possible. This additional context helps the maintainers to
94 | understand the enhancement from your perspective
95 | * **Explain why this enhancement would be useful** to Textile users.
96 | * **Include screenshots and animated GIFs** if relevant to help you demonstrate
97 | the steps or point out the part of Textile which the suggestion is
98 | related to.
99 | * **List some other applications where this enhancement exists, if applicable.**
100 |
101 | ## Additional Notes
102 |
103 | More to be added
104 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 textile.io
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # android-ipfs-lite
2 |
3 | [](https://textile.io)
4 | [](https://slack.textile.io)
5 | [](./LICENSE)
6 | [](https://github.com/textileio/android-ipfs-lite/releases/latest)
7 | [](https://circleci.com/gh/textileio/android-ipfs-lite)
8 | [](https://textileio.github.io/android-ipfs-lite/)
9 | [](https://github.com/RichardLitt/standard-readme)
10 |
11 | > A lightweight, extensible IPFS peer for Android.
12 |
13 | IPFS Lite runs the minimal setup required to get and put IPLD DAGs on the IPFS network. It is a port of the [Go IPFS Lite](https://github.com/hsanjuan/ipfs-lite) library.
14 |
15 | ## Table of Contents
16 |
17 | - [android-ipfs-lite](#android-ipfs-lite)
18 | - [Table of Contents](#table-of-contents)
19 | - [Background](#background)
20 | - [IPFS-lite Libraries](#ipfs-lite-libraries)
21 | - [Roadmap](#roadmap)
22 | - [Install](#install)
23 | - [Usage](#usage)
24 | - [Initialize and start a Peer](#initialize-and-start-a-peer)
25 | - [Add data](#add-data)
26 | - [Add a file](#add-a-file)
27 | - [Fetch a file by CID](#fetch-a-file-by-cid)
28 | - [Maintainers](#maintainers)
29 | - [Contributing](#contributing)
30 | - [License](#license)
31 |
32 | ## Background
33 |
34 | IPFS Lite runs the minimal setup required to provide a DAG service. It is a port of the [Go IPFS Lite](https://github.com/hsanjuan/ipfs-lite) library, and as such, has the same requirements. The goal of IPFS Lite is to run the bare minimal functionality for any IPLD-based application to interact with the IPFS network (by getting and putting blocks). This saves having to deal with the complexities of using a full IPFS daemon, while maintaining the ability to share the underlying libp2p host and DHT with other components.
35 |
36 | ### IPFS-lite Libraries
37 |
38 | > The following includes information about support for ipfs-lite.
39 |
40 | | Name | Build | Language | Description |
41 | |:---------|:---------|:---------|:---------|
42 | | [`ipfs-lite`](https://github.com/hsanjuan/ipfs-lite) | [](https://travis-ci.org/hsanjuan/ipfs-lite) | [](https://github.com/hsanjuan/ipfs-lite) | The reference implementaiton of ipfs-lite, written in Go. |
43 | | [`js-ipfs-lite`](//github.com/textileio/js-ipfs-lite) | [](https://github.com/textileio/js-ipfs-lite/actions?query=branch%3Amaster) | [](https://github.com/textileio/js-ipfs-lite)| The Javascript version of ipfs-lite available for web, nodejs, and React Native applications. |
44 | | [`ios-ipfs-lite`](//github.com/textileio/ios-ipfs-lite) | [](https://github.com/textileio/ios-ipfs-lite/actions?query=branch%3Amaster) | [](https://github.com/textileio/ios-ipfs-lite)| The iOS ipfs-lite library for use in Objc and Swift apps |
45 | | [`android-ipfs-lite`](//github.com/textileio/android-ipfs-lite) | [](https://github.com/textileio/android-ipfs-lite/actions?query=branch%3Amaster) | [](https://github.com/textileio/android-ipfs-lite)| The Java ipfs-lite library for us in Android apps |
46 | | [`grpc-ipfs-lite`](//github.com/textileio/grpc-ipfs-lite) | [](https://github.com/textileio/grpc-ipfs-lite/actions?query=branch%3Amaster) | [](https://github.com/textileio/grpc-ipfs-lite)| A common gRPC API interface that runs on the Go ipfs-lite node. |
47 |
48 | ## Roadmap
49 |
50 | - [x] Start IPFS Lite
51 | - [x] Stop IPFS Lite
52 | - [x] `getFile(String cid)` Get file by Content Address.
53 | - [x] `getFileSync(String cid)` Synchronously get file by Content Address.
54 | - [x] `addFile(byte[] data)` Add file to IPFS.
55 | - [x] `addFileSync(byte[] data)` Synchronously Add file to IPFS.
56 | - [x] `getNode(String cid)` Get IPLD node.
57 | - [x] `removeNode(String cid)` Remove IPLD node.
58 | - [ ] Add IPLD node.
59 | - [x] `resolveLink(String link)`
60 |
61 | ## Install
62 |
63 | The IPFS Lite library is published in [Textile's Bintray Maven repository](https://dl.bintray.com/textile/maven).
64 | You can install it using Gradle.
65 |
66 | First, you'll need to add Textile's Bintray Maven repository to you project's top level `build.gradle` in the `allProjects.repositories` section:
67 |
68 | ```cmd
69 | allprojects {
70 | repositories {
71 | ...
72 | maven { url 'https://dl.bintray.com/textile/maven' }
73 | maven { url 'https://jitpack.io' }
74 | ...
75 | }
76 | }
77 | ```
78 |
79 | Next, add the IPFS Lite dependency to your app module's `build.gradle` `dependencies` section, specifying the [latest version available](https://bintray.com/textile/maven/ipfs-lite/_latestVersion):
80 |
81 | ```cmd
82 | dependencies {
83 | ...
84 | implementation 'io.textile:ipfslite:0.1.4'
85 | ...
86 | }
87 | ```
88 |
89 | ## Usage
90 |
91 | ### Initialize and start a Peer
92 |
93 | ```java
94 | Boolean debug = false;
95 | Peer litePeer = new Peer('/path/', debug, true);
96 | litePeer.start();
97 | ```
98 |
99 | * To learn see how a path is choosen, see the [test suite example](https://github.com/textileio/android-ipfs-lite/blob/master/ipfslite/src/androidTest/java/io/textile/ipfslite/PeerTest.java#L38).
100 |
101 | ### Add data
102 |
103 | ```java
104 | String message = "Hello World";
105 | String cid = litePeer.addFileSync(message.getBytes());
106 | ```
107 |
108 | ### Add a file
109 |
110 | ```java
111 | File file = openFile("secret_plans");
112 | byte[] bytes = Files.readAllBytes(file.toPath());
113 | String cid = litePeer.addFileSync(bytes);
114 |
115 | // OR Asynchronously
116 | litePeer.addFile(bytes, resultHandler);
117 | ```
118 |
119 | ### Fetch a file by CID
120 |
121 | ```java
122 | byte[] data = litePeer.getFileSync("bafybeic35nent64fowmiohupnwnkfm2uxh6vpnyjlt3selcodjipfrokgi");
123 | // OR Asynchronously
124 | litePeer.getFile("bafybeic35nent64fowmiohupnwnkfm2uxh6vpnyjlt3selcodjipfrokgi", resultHandler);
125 | ```
126 |
127 | ## Maintainers
128 |
129 | [Andrew Hill](https://github.com/andrewxhill)
130 |
131 | ## Contributing
132 |
133 | See [the contributing file](CONTRIBUTING.md)!
134 |
135 | PRs accepted.
136 |
137 | Small note: If editing the README, please conform to the [standard-readme](https://github.com/RichardLitt/standard-readme) specification.
138 |
139 | ## License
140 |
141 | [MIT](LICENSE) (c) 2019 Textile
142 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | repositories {
4 | maven {
5 | url 'https://dl.bintray.com/textile/maven'
6 | }
7 | }
8 |
9 | android {
10 | compileSdkVersion targetSdk
11 |
12 | defaultConfig {
13 | applicationId demoAppId
14 | minSdkVersion minSdk
15 | targetSdkVersion targetSdk
16 | versionCode 1
17 | versionName '1.0'
18 |
19 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
20 | }
21 |
22 | buildTypes {
23 | release {
24 | minifyEnabled false
25 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
26 | }
27 | }
28 |
29 | compileOptions {
30 | sourceCompatibility JavaVersion.VERSION_1_8
31 | targetCompatibility JavaVersion.VERSION_1_8
32 | }
33 | }
34 |
35 | dependencies {
36 | implementation fileTree(dir: 'libs', include: ['*.jar'])
37 |
38 | // UI
39 | implementation "com.android.support.constraint:constraint-layout:$constraintLayoutVersion"
40 |
41 | // Support
42 | implementation "com.android.support:appcompat-v7:$appcompatVersion"
43 | implementation "com.android.support:support-v4:$appcompatVersion"
44 |
45 | // gRPC IPFS Lite
46 | implementation project(':ipfslite')
47 |
48 | // Testing
49 | testImplementation "junit:junit:$junitVersion"
50 |
51 | androidTestImplementation "com.android.support.test:runner:$testRunnerVersion"
52 | }
53 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/io/textile/textileexample/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package io.textile.textileexample;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.assertEquals;
11 |
12 | /**
13 | * Instrumented test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
23 |
24 | assertEquals("io.textile.textile.test", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/app/src/main/java/io/textile/textileexample/MainActivity.java:
--------------------------------------------------------------------------------
1 | package io.textile.textileexample;
2 |
3 | import android.content.Context;
4 | import android.os.Bundle;
5 | import android.support.v7.app.AppCompatActivity;
6 | import android.view.View;
7 |
8 | import java.io.File;
9 |
10 | import io.textile.ipfslite.Peer;
11 |
12 | public class MainActivity extends AppCompatActivity {
13 |
14 | Peer litePeer;
15 |
16 | @Override
17 | protected void onCreate(Bundle savedInstanceState) {
18 | super.onCreate(savedInstanceState);
19 | setContentView(R.layout.activity_main);
20 |
21 | initIPFS();
22 | }
23 |
24 | public void onButtonClick(View v) {
25 | try {
26 | String cid = litePeer.addFileSync("Hello World".getBytes());
27 | System.out.println("Success: " + cid);
28 | } catch (Exception e) {
29 | System.out.println(e.getMessage());
30 | }
31 | try {
32 | byte[] file = litePeer.getFileSync("bafybeic35nent64fowmiohupnwnkfm2uxh6vpnyjlt3selcodjipfrokgi");
33 | System.out.println("Success: " + new String(file, "UTF-8"));
34 | } catch (Exception e) {
35 | System.out.println(e.getMessage());
36 | }
37 | }
38 |
39 | private void initIPFS() {
40 | try {
41 | Context ctx = getApplicationContext();
42 | final File filesDir = ctx.getFilesDir();
43 | final String path = new File(filesDir, "ipfslite").getAbsolutePath();
44 | litePeer = new Peer(path, BuildConfig.DEBUG, true);
45 | litePeer.start();
46 | } catch (Exception e) {
47 | System.out.println(e.getMessage());
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
18 |
19 |
35 |
36 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/textileio/android-ipfs-lite/072e039569db16f2fa93108e58094d9139a900dd/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/textileio/android-ipfs-lite/072e039569db16f2fa93108e58094d9139a900dd/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/textileio/android-ipfs-lite/072e039569db16f2fa93108e58094d9139a900dd/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/textileio/android-ipfs-lite/072e039569db16f2fa93108e58094d9139a900dd/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/textileio/android-ipfs-lite/072e039569db16f2fa93108e58094d9139a900dd/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/textileio/android-ipfs-lite/072e039569db16f2fa93108e58094d9139a900dd/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/textileio/android-ipfs-lite/072e039569db16f2fa93108e58094d9139a900dd/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/textileio/android-ipfs-lite/072e039569db16f2fa93108e58094d9139a900dd/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/textileio/android-ipfs-lite/072e039569db16f2fa93108e58094d9139a900dd/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/textileio/android-ipfs-lite/072e039569db16f2fa93108e58094d9139a900dd/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #008577
4 | #00574B
5 | #D81B60
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | TextileExample
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/test/java/io/textile/textileexample/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package io.textile.textileexample;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | apply from: './manifest.gradle'
3 |
4 | repositories {
5 | google()
6 | jcenter()
7 | }
8 | dependencies {
9 | classpath "com.android.tools.build:gradle:$gradleVersion"
10 | classpath "com.github.dcendents:android-maven-gradle-plugin:$mavenGradleVersion"
11 | classpath "com.jfrog.bintray.gradle:gradle-bintray-plugin:$bintrayPluginVersion"
12 | classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.10'
13 | }
14 | }
15 |
16 | allprojects {
17 | repositories {
18 | google()
19 | jcenter()
20 | maven {
21 | url 'https://jitpack.io'
22 | }
23 | }
24 | }
25 |
26 | task clean(type: Delete) {
27 | delete rootProject.buildDir
28 | }
29 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx1536m
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # The following android settings are required in order to solve manifest merge
15 | # issue with net.gotev:uploadservice-okhttp:3.5.2
16 | # > https://github.com/material-components/material-components-android/issues/193#issuecomment-450471987
17 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/textileio/android-ipfs-lite/072e039569db16f2fa93108e58094d9139a900dd/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sun Jun 23 12:11:55 PDT 2019
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/ipfslite/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/ipfslite/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'com.github.dcendents.android-maven'
3 | apply plugin: 'com.jfrog.bintray'
4 | apply plugin: 'com.google.protobuf'
5 |
6 | repositories {
7 | maven {
8 | url 'https://dl.bintray.com/textile/maven'
9 | }
10 | }
11 |
12 | android {
13 | compileSdkVersion targetSdk
14 |
15 | defaultConfig {
16 | minSdkVersion minSdk
17 | targetSdkVersion targetSdk
18 | versionCode 1
19 | versionName '1.0'
20 |
21 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
22 | }
23 |
24 | testOptions {
25 | unitTests {
26 | includeAndroidResources = true
27 | }
28 | }
29 |
30 | buildTypes {
31 | release {
32 | minifyEnabled false
33 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
34 | }
35 | }
36 |
37 | compileOptions {
38 | sourceCompatibility JavaVersion.VERSION_1_8
39 | targetCompatibility JavaVersion.VERSION_1_8
40 | }
41 | sourceSets {
42 | main {
43 | java {
44 | srcDirs 'build/generated/source/proto/debug/grpc'
45 | srcDirs 'build/generated/source/proto/debug/java'
46 | }
47 | }
48 | }
49 |
50 | }
51 |
52 | dependencies {
53 | // gRPC IPFS Lite
54 | api "io.textile:grpc-ipfs-lite:$gRPCIpfsVersion"
55 |
56 | implementation "io.grpc:grpc-core:$gRPCVersion"
57 | implementation "io.grpc:grpc-okhttp:$gRPCVersion"
58 | testImplementation "io.grpc:grpc-testing:$gRPCVersion"
59 | implementation "io.grpc:grpc-stub:$gRPCVersion"
60 |
61 | // Lite, use below for Full
62 | implementation "io.grpc:grpc-protobuf-lite:$gRPCVersion"
63 | // Full proto libs
64 | // implementation "io.grpc:grpc-protobuf:$gRPCVersion"
65 | // implementation "com.google.protobuf:protobuf-java-util:$protobufVersion"
66 |
67 | // Support
68 | implementation "com.android.support:appcompat-v7:$appcompatVersion"
69 | implementation "com.android.support:support-v4:$appcompatVersion"
70 |
71 | // Lifecycle
72 | implementation "android.arch.lifecycle:extensions:$lifecycleVersion"
73 | annotationProcessor "android.arch.lifecycle:compiler:$lifecycleVersion"
74 | compileOnly "javax.annotation:javax.annotation-api:1.2"
75 |
76 | // Testing
77 | testImplementation "junit:junit:$junitVersion"
78 |
79 | // Core library
80 | androidTestImplementation "com.android.support.test:runner:$testRunnerVersion"
81 |
82 | // Utils
83 | androidTestImplementation "org.awaitility:awaitility:$awaitilityVersion"
84 | androidTestImplementation "commons-io:commons-io:$commonsIOVersion"
85 | }
86 |
87 | group = publishedGroupId
88 | version = libraryVersion
89 |
90 | install {
91 | repositories.mavenInstaller {
92 | pom.project {
93 | packaging 'aar'
94 | groupId publishedGroupId
95 | artifactId artifact
96 |
97 | name libraryName
98 | description libraryDescription
99 | url siteUrl
100 |
101 | licenses {
102 | license {
103 | name licenseName
104 | url licenseUrl
105 | }
106 | }
107 | developers {
108 | developer {
109 | id developerId
110 | name developerName
111 | email developerEmail
112 | }
113 | }
114 | scm {
115 | connection gitUrl
116 | developerConnection gitUrl
117 | url siteUrl
118 | }
119 | }
120 |
121 | pom.withXml {
122 | def dependenciesNode = asNode().getAt('dependencies')[0] ?: asNode().appendNode('dependencies')
123 | // Iterate over the implementation dependencies (we don't want the test ones), adding a node for each
124 | configurations.implementation.allDependencies.each {
125 | // Ensure dependencies such as fileTree are not included.
126 | if (it.name != 'unspecified') {
127 | def dependencyNode = dependenciesNode.appendNode('dependency')
128 | dependencyNode.appendNode('groupId', it.group)
129 | dependencyNode.appendNode('artifactId', it.name)
130 | dependencyNode.appendNode('version', it.version)
131 | }
132 | }
133 | }
134 | }
135 | }
136 |
137 | task sourcesJar(type: Jar) {
138 | classifier = 'sources'
139 | from android.sourceSets.main.java.srcDirs
140 | }
141 |
142 | // Build docs
143 | /**
144 | task javadoc(type: Javadoc) {
145 | source = android.sourceSets.main.java.srcDirs
146 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
147 | destinationDir = new File("$rootProject.projectDir/docs")
148 | }
149 |
150 | afterEvaluate {
151 | javadoc.classpath += files(android.libraryVariants.collect { variant ->
152 | variant.javaCompileProvider.get().classpath.files
153 | })
154 | }
155 |
156 | task javadocJar(type: Jar, dependsOn: javadoc) {
157 | classifier = 'javadoc'
158 | from javadoc.destinationDir
159 | }
160 |
161 | artifacts {
162 | archives javadocJar
163 | archives sourcesJar
164 | }
165 | */
166 |
167 | artifacts {
168 | archives sourcesJar
169 | }
170 |
171 | bintray {
172 | user = String.valueOf(System.getenv('BINTRAY_USERNAME'))
173 | key = String.valueOf(System.getenv('BINTRAY_API_KEY'))
174 |
175 | configurations = ['archives']
176 | pkg {
177 | repo = bintrayRepo
178 | name = bintrayName
179 | desc = libraryDescription
180 | websiteUrl = siteUrl
181 | vcsUrl = gitUrl
182 | licenses = allLicenses
183 | dryRun = false
184 | publish = true
185 | override = false
186 | publicDownloadNumbers = true
187 | version {
188 | desc = libraryDescription
189 | }
190 | }
191 | }
192 |
193 | protobuf {
194 | protoc {
195 | artifact = "com.google.protobuf:protoc:3.9.1"
196 | }
197 | plugins {
198 | grpc {
199 | artifact = "io.grpc:protoc-gen-grpc-java:$gRPCVersion"
200 | }
201 | javalite {
202 | artifact = "com.google.protobuf:protoc-gen-javalite:3.11.2"
203 | }
204 | }
205 | generateProtoTasks {
206 | all()*.plugins {
207 | java {
208 | option 'lite'
209 | }
210 | grpc {
211 | // remove for full
212 | option 'lite'
213 | }
214 | }
215 | }
216 | generatedFilesBaseDir = "$projectDir/build/generated"
217 | }
218 |
--------------------------------------------------------------------------------
/ipfslite/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/ipfslite/src/androidTest/assets/TEST0.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/textileio/android-ipfs-lite/072e039569db16f2fa93108e58094d9139a900dd/ipfslite/src/androidTest/assets/TEST0.JPG
--------------------------------------------------------------------------------
/ipfslite/src/androidTest/assets/TEST1.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/textileio/android-ipfs-lite/072e039569db16f2fa93108e58094d9139a900dd/ipfslite/src/androidTest/assets/TEST1.JPG
--------------------------------------------------------------------------------
/ipfslite/src/androidTest/assets/TEST2.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/textileio/android-ipfs-lite/072e039569db16f2fa93108e58094d9139a900dd/ipfslite/src/androidTest/assets/TEST2.JPG
--------------------------------------------------------------------------------
/ipfslite/src/androidTest/assets/TEST3.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/textileio/android-ipfs-lite/072e039569db16f2fa93108e58094d9139a900dd/ipfslite/src/androidTest/assets/TEST3.JPG
--------------------------------------------------------------------------------
/ipfslite/src/androidTest/assets/TEST4.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/textileio/android-ipfs-lite/072e039569db16f2fa93108e58094d9139a900dd/ipfslite/src/androidTest/assets/TEST4.JPG
--------------------------------------------------------------------------------
/ipfslite/src/androidTest/assets/TEST5.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/textileio/android-ipfs-lite/072e039569db16f2fa93108e58094d9139a900dd/ipfslite/src/androidTest/assets/TEST5.JPG
--------------------------------------------------------------------------------
/ipfslite/src/androidTest/assets/TEST6.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/textileio/android-ipfs-lite/072e039569db16f2fa93108e58094d9139a900dd/ipfslite/src/androidTest/assets/TEST6.JPG
--------------------------------------------------------------------------------
/ipfslite/src/androidTest/assets/TEST7.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/textileio/android-ipfs-lite/072e039569db16f2fa93108e58094d9139a900dd/ipfslite/src/androidTest/assets/TEST7.JPG
--------------------------------------------------------------------------------
/ipfslite/src/androidTest/java/io/textile/ipfslite/PeerTest.java:
--------------------------------------------------------------------------------
1 | package io.textile.ipfslite;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.apache.commons.io.FileUtils;
8 | import org.junit.FixMethodOrder;
9 | import org.junit.Test;
10 | import org.junit.runner.RunWith;
11 | import org.junit.runners.MethodSorters;
12 |
13 | import java.io.ByteArrayOutputStream;
14 | import java.io.File;
15 | import java.io.FileOutputStream;
16 | import java.io.IOException;
17 | import java.io.InputStream;
18 | import java.nio.file.Files;
19 | import java.util.List;
20 | import java.util.concurrent.CountDownLatch;
21 | import java.util.concurrent.TimeUnit;
22 | import java.util.concurrent.atomic.AtomicBoolean;
23 | import java.util.concurrent.atomic.AtomicReference;
24 | import java.util.logging.Level;
25 | import java.util.logging.Logger;
26 |
27 | import io.textile.grpc_ipfs_lite.Link;
28 | import io.textile.grpc_ipfs_lite.Node;
29 |
30 | import static org.awaitility.Awaitility.await;
31 | import static org.junit.Assert.assertNull;
32 | import static org.junit.Assert.assertEquals;
33 | import static org.junit.Assert.assertArrayEquals;
34 | import static org.junit.Assert.assertNotNull;
35 |
36 | /**
37 | * Textile tests.
38 | */
39 | @RunWith(AndroidJUnit4.class)
40 | @FixMethodOrder(MethodSorters.NAME_ASCENDING)
41 | public class PeerTest {
42 |
43 | private final static Logger logger =
44 | Logger.getLogger("TEST");
45 |
46 | static String COMMON_CID = "QmWATWQ7fVPP2EFGu71UkfnqhYXDYH566qy47CnJDgvs8u";
47 | static String HELLO_WORLD_CID = "bafybeic35nent64fowmiohupnwnkfm2uxh6vpnyjlt3selcodjipfrokgi";
48 | static String HELLO_WORLD = "Hello World";
49 | static String TEST1_CID = "bafybeifi4myu2s6rkegzeb2qk6znfg76lt4gpqe6sftozg3rjy6a5cw4qa";
50 | static String REPO_NAME = "ipfslite";
51 |
52 | static Peer litePeer;
53 |
54 | String createRepo(Boolean reset) throws Exception {
55 | Context ctx = InstrumentationRegistry.getInstrumentation().getTargetContext();
56 |
57 | final File filesDir = ctx.getFilesDir();
58 | final String path = new File(filesDir, REPO_NAME).getAbsolutePath();
59 | // Wipe repo
60 | File repo = new File(path);
61 | if (repo.exists() && reset == true) {
62 | FileUtils.deleteDirectory(repo);
63 | }
64 | return path;
65 | }
66 |
67 | void startPeer() throws Exception {
68 | // Initialize & start
69 | litePeer = new Peer(createRepo(true), BuildConfig.DEBUG, true);
70 | litePeer.start();
71 | }
72 |
73 | @Test
74 | public void startTest() throws Exception {
75 | startPeer();
76 | assertEquals(true, litePeer.started());
77 | }
78 |
79 | @Test
80 | public void GetFileSync() throws Exception {
81 | if (litePeer == null) {
82 | startPeer();
83 | }
84 |
85 | byte[] file = litePeer.getFileSync(COMMON_CID);
86 |
87 | assertNotNull(file);
88 | }
89 | @Test
90 | public void GetFile() throws Exception {
91 | if (litePeer == null) {
92 | startPeer();
93 | }
94 |
95 | // Make the CID locally available
96 | litePeer.addFileSync(HELLO_WORLD.getBytes());
97 |
98 | final CountDownLatch finishLatch = new CountDownLatch(1);
99 |
100 | // byte array to build
101 | ByteArrayOutputStream output = new ByteArrayOutputStream();
102 |
103 | // Async call
104 | litePeer.getFile(
105 | HELLO_WORLD_CID, new Peer.GetFileHandler() {
106 | @Override
107 | public void onNext(byte[] data) {
108 | try {
109 | logger.log(Level.INFO, "" + data.length);
110 | output.write(data);
111 | } catch (Throwable t) {
112 | assertNull(t);
113 | finishLatch.countDown();
114 | }
115 |
116 | }
117 |
118 | @Override
119 | public void onError(Throwable t) {
120 | assertNull(t);
121 | finishLatch.countDown();
122 | }
123 |
124 | @Override
125 | public void onComplete() {
126 | byte[] result = output.toByteArray();
127 | try {
128 | String resultString = new String(result, "UTF-8");
129 | assertEquals(HELLO_WORLD, resultString);
130 | } catch (Throwable t) {
131 | assertNull(t);
132 | }
133 | finishLatch.countDown();
134 | }
135 | });
136 | // Await async call
137 | finishLatch.await(30, TimeUnit.SECONDS);
138 | }
139 |
140 | @Test
141 | public void ResolveLink() throws Exception {
142 | if (litePeer == null) {
143 | startPeer();
144 | }
145 |
146 | final CountDownLatch finishLatch = new CountDownLatch(1);
147 | final AtomicReference CID = new AtomicReference<>("");
148 | String link = "QmSnuWmxptJZdLJpKRarxBMS2Ju2oANVrgbr2xWbie9b2D/README.txt";
149 |
150 | litePeer.resolveLink(
151 | link,
152 | new Peer.ResolveLinkHandler() {
153 | @Override
154 | public void onNext(String cid) {
155 | logger.log(Level.INFO, "CID: " + cid);
156 | CID.set(cid);
157 | }
158 |
159 | @Override
160 | public void onError(Throwable t) {
161 | assertNull(t);
162 | finishLatch.countDown();
163 | }
164 |
165 | @Override
166 | public void onComplete() {
167 | finishLatch.countDown();
168 | }
169 | }
170 | );
171 | // Await async call
172 | finishLatch.await(30, TimeUnit.SECONDS);
173 | assertEquals("QmP8jTG1m9GSDJLCbeWhVSVgEzCPPwXRdCRuJtQ5Tz9Kc9", CID.get());
174 | }
175 |
176 | @Test
177 | public void GetNode() throws Exception {
178 | if (litePeer == null) {
179 | startPeer();
180 | }
181 |
182 | final CountDownLatch finishLatch = new CountDownLatch(1);
183 | final AtomicReference LINKS = new AtomicReference<>(0);
184 | String link = "QmSnuWmxptJZdLJpKRarxBMS2Ju2oANVrgbr2xWbie9b2D";
185 |
186 | litePeer.getNode(
187 | link,
188 | new Peer.ResolveNodeHandler() {
189 | @Override
190 | public void onNext(Node node) {
191 | logger.log(Level.INFO, "Links: " + node.getLinksCount());
192 | LINKS.set(node.getLinksCount());
193 | List links = node.getLinksList();
194 | for (int i = 0; i < links.size(); i++) {
195 | logger.log(Level.INFO, links.get(i).getName() + ": " + links.get(i).getCid());
196 | }
197 |
198 | }
199 |
200 | @Override
201 | public void onError(Throwable t) {
202 | assertNull(t);
203 | finishLatch.countDown();
204 | }
205 |
206 | @Override
207 | public void onComplete() {
208 | finishLatch.countDown();
209 | }
210 | }
211 | );
212 | // Await async call
213 | finishLatch.await(30, TimeUnit.SECONDS);
214 | Integer expected = 6;
215 | assertEquals(expected, LINKS.get());
216 | }
217 |
218 | @Test
219 | public void AddFileSync() throws Exception {
220 | if (litePeer == null) {
221 | startPeer();
222 | assertEquals(true, litePeer.started());
223 | }
224 | String cid = litePeer.addFileSync(HELLO_WORLD.getBytes());
225 | assertEquals(HELLO_WORLD_CID, cid);
226 |
227 | byte[] res = litePeer.getFileSync(HELLO_WORLD_CID);
228 | assertEquals(HELLO_WORLD, new String(res, "UTF-8"));
229 | }
230 |
231 | @Test
232 | public void AddFile() throws Exception {
233 | if (litePeer == null) {
234 | startPeer();
235 | assertEquals(true, litePeer.started());
236 | }
237 |
238 | // Make the CID locally available
239 | litePeer.addFileSync(HELLO_WORLD.getBytes());
240 |
241 | AtomicBoolean ready = new AtomicBoolean();
242 | final AtomicReference CID = new AtomicReference<>("");
243 |
244 | // Async call
245 | litePeer.addFile(
246 | HELLO_WORLD.getBytes(), new Peer.AddFileHandler() {
247 | @Override
248 | public void onNext(String cid) {
249 | CID.set(cid);
250 | }
251 |
252 | @Override
253 | public void onError(Throwable t) {
254 | assertNull(t);
255 | ready.getAndSet(true);
256 | }
257 |
258 | @Override
259 | public void onComplete() {
260 | String result = CID.get();
261 | assertEquals(HELLO_WORLD_CID, result);
262 | ready.getAndSet(true);
263 | }
264 | });
265 | // Await async call
266 | await().atMost(30, TimeUnit.SECONDS).untilTrue(ready);
267 | }
268 |
269 |
270 | @Test
271 | public void AddThenGetImage() throws Exception {
272 | if (litePeer == null) {
273 | startPeer();
274 | assertEquals(true, litePeer.started());
275 | }
276 |
277 | Context ctx = InstrumentationRegistry.getInstrumentation().getTargetContext();
278 | File input1 = PeerTest.getCacheFile(ctx, "TEST1.JPG");
279 |
280 | byte[] fileBytes = Files.readAllBytes(input1.toPath());
281 | String cid = litePeer.addFileSync(fileBytes);
282 | assertEquals(TEST1_CID, cid);
283 |
284 | byte[] res = litePeer.getFileSync(TEST1_CID);
285 | assertArrayEquals(fileBytes, res);
286 | }
287 |
288 | private static File getCacheFile(Context context, String filename) throws IOException {
289 | File file = new File(context.getCacheDir(), filename);
290 | InputStream inputStream = context.getAssets().open(filename);
291 | try (FileOutputStream outputStream = new FileOutputStream(file)) {
292 | try {
293 | byte[] buf = new byte[1024];
294 | int len;
295 | while ((len = inputStream.read(buf)) > 0) {
296 | outputStream.write(buf, 0, len);
297 | }
298 | } finally {
299 | outputStream.close();
300 | }
301 | }
302 | return file;
303 | }
304 | }
305 |
--------------------------------------------------------------------------------
/ipfslite/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/ipfslite/src/main/java/io/textile/ipfslite/Peer.java:
--------------------------------------------------------------------------------
1 | package io.textile.ipfslite;
2 |
3 | import java.io.ByteArrayOutputStream;
4 | import java.util.Arrays;
5 | import java.util.LinkedList;
6 | import java.util.concurrent.atomic.AtomicReference;
7 | import java.util.logging.Level;
8 | import java.util.logging.Logger;
9 |
10 | import android.arch.lifecycle.LifecycleObserver;
11 |
12 | import com.google.protobuf.ByteString;
13 |
14 | import io.grpc.ManagedChannel;
15 | import io.grpc.ManagedChannelBuilder;
16 |
17 | import java.util.Iterator;
18 | import java.util.concurrent.CountDownLatch;
19 | import java.util.concurrent.TimeUnit;
20 |
21 | // This is the gRPC IPFS Lite gomobile framework output
22 | import io.grpc.stub.StreamObserver;
23 | import mobile.Mobile;
24 |
25 | // This is the proto generated services and methods
26 | import io.textile.grpc_ipfs_lite.*;
27 |
28 | class PeerException extends Exception
29 | {
30 | public PeerException(String message)
31 | {
32 | super(message);
33 | }
34 | }
35 |
36 | /**
37 | * Provides top level access to the Textile API
38 | */
39 | public class Peer implements LifecycleObserver {
40 |
41 | private static final String TAG = "Peer";
42 | private final static Logger logger =
43 | Logger.getLogger(TAG);
44 |
45 | private static Boolean mem;
46 | private static Boolean mode;
47 | public static String path;
48 | private static long port;
49 |
50 | private static ManagedChannel channel;
51 | private static IpfsLiteGrpc.IpfsLiteBlockingStub blockingStub;
52 | private static IpfsLiteGrpc.IpfsLiteStub asyncStub;
53 |
54 | enum NodeState {
55 | Start, Stop
56 | }
57 |
58 | public static NodeState state = NodeState.Stop;
59 |
60 | /**
61 | * init the gRPC IPFS Lite server instance with the provided repo path
62 | */
63 | public Peer(String datastorePath, Boolean debug, Boolean lowMem) {
64 | path = datastorePath;
65 | mode = debug;
66 | mem = lowMem;
67 | }
68 |
69 | void ready() throws PeerException {
70 | if (!started()) {
71 | throw new PeerException("Peer not started");
72 | }
73 | }
74 |
75 | /**
76 | * start IPFS Lite instance with the provided repo path
77 | * @throws Exception The exception that occurred
78 | */
79 | public static void start() throws Exception {
80 | if (state == NodeState.Start) {
81 | return;
82 | }
83 | port = Mobile.start(path, mode, mem);
84 |
85 | channel = ManagedChannelBuilder
86 | .forAddress("localhost", Math.toIntExact(port))
87 | .usePlaintext()
88 | .build();
89 | blockingStub = IpfsLiteGrpc.newBlockingStub(channel);
90 | asyncStub = IpfsLiteGrpc.newStub(channel);
91 |
92 | state = NodeState.Start;
93 | }
94 |
95 | public static void stop() throws Exception {
96 | if (state == NodeState.Stop) {
97 | return;
98 | }
99 | Mobile.stop();
100 | state = NodeState.Stop;
101 | }
102 |
103 | static GetFileRequest FileRequest (String cid) {
104 | return GetFileRequest.newBuilder()
105 | .setCid(cid)
106 | .build();
107 | }
108 |
109 | static AddParams.Builder AddFileParams (ByteString data) {
110 | return AddParams.newBuilder()
111 | .setChunker(data.toStringUtf8());
112 | }
113 | static AddFileRequest.Builder FileData (ByteString data) {
114 | return AddFileRequest.newBuilder()
115 | .setAddParams(AddFileParams(data))
116 | .setChunk(data);
117 | }
118 | static AddFileRequest.Builder FileRequestHeader () {
119 | AddParams.Builder params = AddParams.newBuilder();
120 | return AddFileRequest.newBuilder()
121 | .setAddParams(params);
122 | }
123 |
124 | void streamDataChunks(byte[] data, StreamObserver requestStream) {
125 | try {
126 | // Start stream
127 | AddFileRequest.Builder requestHeader = FileRequestHeader();
128 | requestStream.onNext(requestHeader.build());
129 | // Send file segments of 1024b
130 | int blockSize = 1024;
131 | int blockCount = (data.length + blockSize - 1) / blockSize;
132 |
133 | byte[] range;
134 | for (int i = 1; i < blockCount; i++) {
135 | int idx = (i - 1) * blockSize;
136 | range = Arrays.copyOfRange(data, idx, idx + blockSize);
137 | AddFileRequest.Builder requestData = FileData(ByteString.copyFrom(range));
138 | requestStream.onNext(requestData.build());
139 | }
140 | int end = -1;
141 | if (data.length % blockSize == 0) {
142 | end = data.length;
143 | } else {
144 | end = data.length % blockSize + blockSize * (blockCount - 1);
145 | }
146 | range = Arrays.copyOfRange(data, (blockCount - 1) * blockSize, end);
147 | AddFileRequest.Builder requestData = FileData(ByteString.copyFrom(range));
148 | requestStream.onNext(requestData.build());
149 | } catch (RuntimeException e) {
150 | requestStream.onError(e);
151 | throw e;
152 | }
153 | requestStream.onCompleted();
154 | }
155 |
156 | public interface AddFileHandler {
157 | void onNext(final String cid);
158 | void onComplete();
159 | void onError(final Throwable t);
160 | }
161 |
162 | public void addFile(byte[] data, final AddFileHandler handler) {
163 |
164 | StreamObserver addFileRequest = asyncStub.addFile(new StreamObserver() {
165 | @Override
166 | public void onNext(AddFileResponse value) {
167 | try {
168 | String cid = value.getNode().getBlock().getCid();
169 | handler.onNext(cid);
170 | } catch (Throwable t) {
171 | handler.onError(t);
172 | }
173 | }
174 |
175 | @Override
176 | public void onError(Throwable t) {
177 | logger.log(Level.INFO, "GetFileError: " + t.getLocalizedMessage());
178 | handler.onError(t);
179 | }
180 |
181 | @Override
182 | public void onCompleted() {
183 | logger.log(Level.INFO, "GetFileComplete");
184 | handler.onComplete();
185 | }
186 | });
187 |
188 | // Stream the file over a background thread
189 | new Thread(() -> {
190 | streamDataChunks(data, addFileRequest);
191 | }).start();
192 | }
193 |
194 | public String addFileSync(byte[] data) throws Exception {
195 | ready();
196 | final CountDownLatch finishLatch = new CountDownLatch(1);
197 | final AtomicReference CID = new AtomicReference<>("");
198 | StreamObserver responseObserver = new StreamObserver() {
199 | @Override
200 | public void onNext(AddFileResponse value) {
201 | String res = value.getNode().getBlock().getCid();
202 | logger.log(Level.INFO, "AddFile onNext: " + res);
203 | CID.set(res);
204 | }
205 |
206 | @Override
207 | public void onError(Throwable t) {
208 | logger.log(Level.INFO, "AddFile onError: " + t.getLocalizedMessage());
209 | finishLatch.countDown();
210 | }
211 |
212 | @Override
213 | public void onCompleted() {
214 | logger.log(Level.INFO, "AddFile: Complete");
215 | finishLatch.countDown();
216 | }
217 | };
218 | StreamObserver addFileRequest = asyncStub.addFile(responseObserver);
219 |
220 | // Stream the file over a background thread
221 | new Thread(() -> {
222 | streamDataChunks(data, addFileRequest);
223 | }).start();
224 |
225 | // this will take as long as you give it.
226 | finishLatch.await(30, TimeUnit.SECONDS);
227 | return CID.get();
228 | }
229 |
230 | public interface GetFileHandler {
231 | void onNext(final byte[] data);
232 | void onComplete();
233 | void onError(final Throwable t);
234 | }
235 | public void getFile(String cid, final GetFileHandler handler) {
236 | asyncStub.getFile(FileRequest(cid), new StreamObserver() {
237 | @Override
238 | public void onNext(GetFileResponse value) {
239 | handler.onNext(value.getChunk().toByteArray());
240 | }
241 |
242 | @Override
243 | public void onError(Throwable t) {
244 | logger.log(Level.INFO, "GetFileError: " + t.getLocalizedMessage());
245 | handler.onError(t);
246 | }
247 |
248 | @Override
249 | public void onCompleted() {
250 | logger.log(Level.INFO, "GetFileComplete");
251 | handler.onComplete();
252 | }
253 | });
254 | }
255 |
256 | public byte[] getFileSync(String cid) throws Exception {
257 | ready();
258 | GetFileRequest request = FileRequest(cid);
259 | Iterator response = blockingStub.getFile(request);
260 | // TODO is there a more efficient way to do this?
261 | ByteArrayOutputStream baos = new ByteArrayOutputStream();
262 | while (response.hasNext()) {
263 | byte[] bytes = response.next().getChunk().toByteArray();
264 | baos.write(bytes);
265 | }
266 | return baos.toByteArray();
267 | }
268 |
269 | public interface ResolveLinkHandler {
270 | void onNext(final String cid);
271 | void onComplete();
272 | void onError(final Throwable t);
273 | }
274 |
275 | public void resolveLink(String link, final ResolveLinkHandler handler) {
276 | String[] parts = link.split("/");
277 | if (parts.length == 0) {
278 | handler.onComplete();
279 | }
280 |
281 | ResolveLinkRequest.Builder request = ResolveLinkRequest
282 | .newBuilder()
283 | .setNodeCid(parts[0]);
284 |
285 |
286 | String linkPath = link.replace(parts[0] + "/", "");
287 | if (linkPath != "") {
288 | request.addPath(linkPath);
289 | }
290 |
291 | asyncStub.resolveLink(request.build(), new StreamObserver() {
292 | @Override
293 | public void onNext(ResolveLinkResponse value) {
294 | handler.onNext(value.getLink().getCid());
295 | }
296 |
297 | @Override
298 | public void onError(Throwable t) {
299 | logger.log(Level.INFO, "ResolveLinkResponseError: " + t.getLocalizedMessage());
300 | handler.onError(t);
301 | }
302 |
303 | @Override
304 | public void onCompleted() {
305 | logger.log(Level.INFO, "ResolveLinkResponseComplete");
306 | handler.onComplete();
307 | }
308 | });
309 | }
310 |
311 | public interface ResolveNodeHandler {
312 | void onNext(final Node node);
313 | void onComplete();
314 | void onError(final Throwable t);
315 | }
316 |
317 | public void getNode(String cid, final ResolveNodeHandler handler) {
318 | GetNodeRequest.Builder request = GetNodeRequest
319 | .newBuilder()
320 | .setCid(cid);
321 |
322 | asyncStub.getNode(request.build(), new StreamObserver() {
323 | @Override
324 | public void onNext(GetNodeResponse value) {
325 | Node node = value.getNode();
326 | handler.onNext(node);
327 | }
328 |
329 | @Override
330 | public void onError(Throwable t) {
331 | logger.log(Level.INFO, "GetNodeError: " + t.getLocalizedMessage());
332 | handler.onError(t);
333 | }
334 |
335 | @Override
336 | public void onCompleted() {
337 | logger.log(Level.INFO, "GetNodeComplete");
338 | handler.onComplete();
339 | }
340 | });
341 | }
342 |
343 | public interface RemoveNodeHandler {
344 | void onNext(String cid);
345 | void onComplete();
346 | void onError(final Throwable t);
347 | }
348 | public void removeNode(String cid, final RemoveNodeHandler handler) {
349 | RemoveNodeRequest.Builder request = RemoveNodeRequest
350 | .newBuilder()
351 | .setCid(cid);
352 |
353 | asyncStub.removeNode(request.build(), new StreamObserver() {
354 | @Override
355 | public void onNext(RemoveNodeResponse value) {
356 | handler.onNext(value.toString());
357 | }
358 |
359 | @Override
360 | public void onError(Throwable t) {
361 | logger.log(Level.INFO, "RemoveNodeError: " + t.getLocalizedMessage());
362 | handler.onError(t);
363 | }
364 |
365 | @Override
366 | public void onCompleted() {
367 | logger.log(Level.INFO, "RemoveNodeComplete");
368 | handler.onComplete();
369 | }
370 | });
371 | }
372 |
373 | public Boolean started() {
374 | return state == NodeState.Start;
375 | }
376 | }
--------------------------------------------------------------------------------
/ipfslite/src/main/proto/ipfs_lite.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | option java_multiple_files = true;
4 | option java_package = "io.textile.grpc_ipfs_lite";
5 | option java_outer_classname = "IpfsLiteProto";
6 | option objc_class_prefix = "TTE";
7 |
8 | package ipfs_lite;
9 |
10 | // Model messages
11 |
12 | message AddParams {
13 | string layout = 1;
14 | string chunker = 2;
15 | bool rawLeaves = 3;
16 | bool hidden = 4;
17 | bool shared = 5;
18 | bool noCopy = 6;
19 | string hashFun = 7;
20 | }
21 |
22 | message Block {
23 | bytes rawData = 1;
24 | string cid = 2;
25 | }
26 |
27 | message Link {
28 | string name = 1;
29 | int64 size = 2;
30 | string cid = 3;
31 | }
32 |
33 | message NodeStat {
34 | string hash = 1;
35 | int32 numLinks = 2;
36 | int32 blockSize = 3;
37 | int32 linksSize = 4;
38 | int32 dataSize = 5;
39 | int32 cumulativeSize = 6;
40 | }
41 |
42 | message Node {
43 | Block block = 1;
44 | repeated Link links = 2;
45 | NodeStat stat = 3;
46 | int64 size = 4;
47 | }
48 |
49 | // Request and Response messages
50 |
51 | message AddFileRequest {
52 | oneof payload {
53 | AddParams addParams = 1;
54 | bytes chunk = 2;
55 | }
56 | }
57 |
58 | message AddFileResponse {
59 | Node node = 1;
60 | }
61 |
62 | message GetFileRequest {
63 | string cid = 1;
64 | }
65 |
66 | message GetFileResponse {
67 | bytes chunk = 1;
68 | }
69 |
70 | message AddNodeRequest {
71 | Block block = 1;
72 | }
73 |
74 | message AddNodeResponse {
75 |
76 | }
77 |
78 | message AddNodesRequest {
79 | repeated Block blocks = 1;
80 | }
81 |
82 | message AddNodesResponse {
83 |
84 | }
85 |
86 | message GetNodeRequest {
87 | string cid = 1;
88 | }
89 |
90 | message GetNodeResponse {
91 | Node node = 1;
92 | }
93 |
94 | message GetNodesRequest {
95 | repeated string cids = 1;
96 | }
97 |
98 | message GetNodesResponse {
99 | oneof option {
100 | Node node = 1;
101 | string error = 2;
102 | }
103 | }
104 |
105 | message RemoveNodeRequest {
106 | string cid = 1;
107 | }
108 |
109 | message RemoveNodeResponse {
110 |
111 | }
112 |
113 | message RemoveNodesRequest {
114 | repeated string cids = 1;
115 | }
116 |
117 | message RemoveNodesResponse {
118 |
119 | }
120 |
121 | message ResolveLinkRequest {
122 | string nodeCid = 1;
123 | repeated string path = 2;
124 | }
125 |
126 | message ResolveLinkResponse {
127 | Link link = 1;
128 | repeated string remainingPath = 2;
129 | }
130 |
131 | message TreeRequest {
132 | string nodeCid = 1;
133 | string path = 2;
134 | int32 depth = 3;
135 | }
136 |
137 | message TreeResponse {
138 | repeated string paths = 1;
139 | }
140 |
141 | message DeleteBlockRequest {
142 | string cid = 1;
143 | }
144 |
145 | message DeleteBlockResponse {
146 |
147 | }
148 |
149 | message HasBlockRequest {
150 | string cid = 1;
151 | }
152 |
153 | message HasBlockResponse {
154 | bool hasBlock = 1;
155 | }
156 |
157 | message GetBlockRequest {
158 | string cid = 1;
159 | }
160 |
161 | message GetBlockResponse {
162 | Block block = 1;
163 | }
164 |
165 | message GetBlockSizeRequest {
166 | string cid = 1;
167 | }
168 |
169 | message GetBlockSizeResponse {
170 | int32 size = 1;
171 | }
172 |
173 | message PutBlockRequest {
174 | Block block = 1;
175 | }
176 |
177 | message PutBlockResponse {
178 |
179 | }
180 |
181 | message PutBlocksRequest {
182 | repeated Block blocks = 1;
183 | }
184 |
185 | message PutBlocksResponse {
186 |
187 | }
188 |
189 | message AllKeysRequest {
190 |
191 | }
192 |
193 | message AllKeysResponse {
194 | string cid = 1;
195 | }
196 |
197 | message HashOnReadRequest {
198 | bool hashOnRead = 1;
199 | }
200 |
201 | message HashOnReadResponse {
202 |
203 | }
204 |
205 | service IpfsLite {
206 | rpc AddFile(stream AddFileRequest) returns (AddFileResponse) {}
207 |
208 | rpc GetFile(GetFileRequest) returns (stream GetFileResponse) {}
209 |
210 | rpc HasBlock(HasBlockRequest) returns (HasBlockResponse) {}
211 |
212 | // DAGService
213 |
214 | rpc AddNode(AddNodeRequest) returns (AddNodeResponse) {}
215 |
216 | rpc AddNodes(AddNodesRequest) returns (AddNodesResponse) {}
217 |
218 | rpc GetNode(GetNodeRequest) returns (GetNodeResponse) {}
219 |
220 | rpc GetNodes(GetNodesRequest) returns (stream GetNodesResponse) {}
221 |
222 | rpc RemoveNode(RemoveNodeRequest) returns (RemoveNodeResponse) {}
223 |
224 | rpc RemoveNodes(RemoveNodesRequest) returns (RemoveNodesResponse) {}
225 |
226 | // Node provides a ResloveLink method and the Resolver methods Resolve and Tree
227 |
228 | rpc ResolveLink(ResolveLinkRequest) returns (ResolveLinkResponse) {}
229 |
230 | rpc Tree(TreeRequest) returns (TreeResponse) {}
231 | }
232 |
--------------------------------------------------------------------------------
/ipfslite/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Textile
3 |
4 |
--------------------------------------------------------------------------------
/ipfslite/src/test/java/io/textile/ipfslite/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package io.textile.ipfslite;
2 |
3 | import org.junit.Test;
4 |
5 |
6 | import static org.junit.Assert.*;
7 |
8 | /**
9 | * Example local unit test, which will execute on the development machine (host).
10 | *
11 | * @see Testing documentation
12 | */
13 | public class ExampleUnitTest {
14 | @Test
15 | public void addition_isCorrect() {
16 | assertEquals(4, 2 + 2);
17 | }
18 | }
--------------------------------------------------------------------------------
/ipfslite/src/test/proto/ipfs_lite.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | option java_multiple_files = true;
4 | option java_package = "io.textile.grpc_ipfs_lite";
5 | option java_outer_classname = "IpfsLiteProto";
6 | option objc_class_prefix = "TTE";
7 |
8 | package ipfs_lite;
9 |
10 | // Model messages
11 |
12 | message AddParams {
13 | string layout = 1;
14 | string chunker = 2;
15 | bool rawLeaves = 3;
16 | bool hidden = 4;
17 | bool shared = 5;
18 | bool noCopy = 6;
19 | string hashFun = 7;
20 | }
21 |
22 | message Block {
23 | bytes rawData = 1;
24 | string cid = 2;
25 | }
26 |
27 | message Link {
28 | string name = 1;
29 | int64 size = 2;
30 | string cid = 3;
31 | }
32 |
33 | message NodeStat {
34 | string hash = 1;
35 | int32 numLinks = 2;
36 | int32 blockSize = 3;
37 | int32 linksSize = 4;
38 | int32 dataSize = 5;
39 | int32 cumulativeSize = 6;
40 | }
41 |
42 | message Node {
43 | Block block = 1;
44 | repeated Link links = 2;
45 | NodeStat stat = 3;
46 | int64 size = 4;
47 | }
48 |
49 | // Request and Response messages
50 |
51 | message AddFileRequest {
52 | oneof payload {
53 | AddParams addParams = 1;
54 | bytes chunk = 2;
55 | }
56 | }
57 |
58 | message AddFileResponse {
59 | Node node = 1;
60 | }
61 |
62 | message GetFileRequest {
63 | string cid = 1;
64 | }
65 |
66 | message GetFileResponse {
67 | bytes chunk = 1;
68 | }
69 |
70 | message AddNodeRequest {
71 | Block block = 1;
72 | }
73 |
74 | message AddNodeResponse {
75 |
76 | }
77 |
78 | message AddNodesRequest {
79 | repeated Block blocks = 1;
80 | }
81 |
82 | message AddNodesResponse {
83 |
84 | }
85 |
86 | message GetNodeRequest {
87 | string cid = 1;
88 | }
89 |
90 | message GetNodeResponse {
91 | Node node = 1;
92 | }
93 |
94 | message GetNodesRequest {
95 | repeated string cids = 1;
96 | }
97 |
98 | message GetNodesResponse {
99 | oneof option {
100 | Node node = 1;
101 | string error = 2;
102 | }
103 | }
104 |
105 | message RemoveNodeRequest {
106 | string cid = 1;
107 | }
108 |
109 | message RemoveNodeResponse {
110 |
111 | }
112 |
113 | message RemoveNodesRequest {
114 | repeated string cids = 1;
115 | }
116 |
117 | message RemoveNodesResponse {
118 |
119 | }
120 |
121 | message ResolveLinkRequest {
122 | string nodeCid = 1;
123 | repeated string path = 2;
124 | }
125 |
126 | message ResolveLinkResponse {
127 | Link link = 1;
128 | repeated string remainingPath = 2;
129 | }
130 |
131 | message TreeRequest {
132 | string nodeCid = 1;
133 | string path = 2;
134 | int32 depth = 3;
135 | }
136 |
137 | message TreeResponse {
138 | repeated string paths = 1;
139 | }
140 |
141 | message DeleteBlockRequest {
142 | string cid = 1;
143 | }
144 |
145 | message DeleteBlockResponse {
146 |
147 | }
148 |
149 | message HasBlockRequest {
150 | string cid = 1;
151 | }
152 |
153 | message HasBlockResponse {
154 | bool hasBlock = 1;
155 | }
156 |
157 | message GetBlockRequest {
158 | string cid = 1;
159 | }
160 |
161 | message GetBlockResponse {
162 | Block block = 1;
163 | }
164 |
165 | message GetBlockSizeRequest {
166 | string cid = 1;
167 | }
168 |
169 | message GetBlockSizeResponse {
170 | int32 size = 1;
171 | }
172 |
173 | message PutBlockRequest {
174 | Block block = 1;
175 | }
176 |
177 | message PutBlockResponse {
178 |
179 | }
180 |
181 | message PutBlocksRequest {
182 | repeated Block blocks = 1;
183 | }
184 |
185 | message PutBlocksResponse {
186 |
187 | }
188 |
189 | message AllKeysRequest {
190 |
191 | }
192 |
193 | message AllKeysResponse {
194 | string cid = 1;
195 | }
196 |
197 | message HashOnReadRequest {
198 | bool hashOnRead = 1;
199 | }
200 |
201 | message HashOnReadResponse {
202 |
203 | }
204 |
205 | service IpfsLite {
206 | rpc AddFile(stream AddFileRequest) returns (AddFileResponse) {}
207 |
208 | rpc GetFile(GetFileRequest) returns (stream GetFileResponse) {}
209 |
210 | rpc HasBlock(HasBlockRequest) returns (HasBlockResponse) {}
211 |
212 | // DAGService
213 |
214 | rpc AddNode(AddNodeRequest) returns (AddNodeResponse) {}
215 |
216 | rpc AddNodes(AddNodesRequest) returns (AddNodesResponse) {}
217 |
218 | rpc GetNode(GetNodeRequest) returns (GetNodeResponse) {}
219 |
220 | rpc GetNodes(GetNodesRequest) returns (stream GetNodesResponse) {}
221 |
222 | rpc RemoveNode(RemoveNodeRequest) returns (RemoveNodeResponse) {}
223 |
224 | rpc RemoveNodes(RemoveNodesRequest) returns (RemoveNodesResponse) {}
225 |
226 | // Node provides a ResloveLink method and the Resolver methods Resolve and Tree
227 |
228 | rpc ResolveLink(ResolveLinkRequest) returns (ResolveLinkResponse) {}
229 |
230 | rpc Tree(TreeRequest) returns (TreeResponse) {}
231 | }
232 |
--------------------------------------------------------------------------------
/manifest.gradle:
--------------------------------------------------------------------------------
1 | ext {
2 | bintrayRepo = 'maven'
3 | bintrayName = 'ipfslite'
4 |
5 | publishedGroupId = 'io.textile'
6 | libraryName = 'ipfslite'
7 | artifact = 'ipfslite'
8 |
9 | demoAppId = 'io.textile.textileexample'
10 |
11 | libraryDescription = 'IPFS Lite for Android'
12 | libraryKeywords = ['textile', 'ipfs', 'libp2p', 'decentralized', 'encrypted', 'android']
13 |
14 | siteUrl = 'https://github.com/textileio/android-ipfs-lite'
15 | gitUrl = 'https://github.com/textileio/android-ipfs-lite.git'
16 |
17 | libraryVersion = '0.1.4'
18 |
19 | minSdk = 26
20 | targetSdk = 28
21 |
22 | // Gradle classpath dependencies versions
23 | gradleVersion = '3.4.1'
24 | mavenGradleVersion = '2.1'
25 | bintrayPluginVersion = '1.7'
26 |
27 | // Library and app testing dependencies versions
28 | junitVersion = '4.12'
29 | // androidxTestCoreVersion = '1.2.0'
30 | // androidxTestRunnerVersion = '1.2.0'
31 | // androidxTestRulesVersion = '1.2.0'
32 | // androidxTestExtJunitVersion = '1.1.1'
33 | // androidxTestExtTruthVersion = '1.2.0'
34 | // androidxTestEspressoVersion = '3.2.0'
35 | testRunnerVersion = '1.0.2'
36 |
37 | // Library and app dependencies versions
38 | // androidxAppcompatVersion = '1.0.2'
39 | appcompatVersion = '28.0.0'
40 |
41 | // gRPC Version
42 | gRPCVersion = '1.26.0'
43 | // gRPC IPFS Lite Version
44 | gRPCIpfsVersion = '0.1.4'
45 |
46 | protobufVersion = '3.10.0'
47 |
48 | // Lifecycle
49 | lifecycleVersion = '1.1.1'
50 |
51 | // Demo App
52 | constraintLayoutVersion = '1.1.3'
53 |
54 | // Demo App Tests
55 | awaitilityVersion = '3.1.6'
56 | commonsIOVersion = '2.6'
57 |
58 | developerId = 'textile'
59 | developerName = 'Textile'
60 | developerEmail = 'contact@textile.io'
61 |
62 | licenseName = 'MIT'
63 | licenseUrl = 'https://github.com/textileio/android-ipfs-lite/blob/master/LICENSE'
64 | allLicenses = ['MIT']
65 | }
66 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':ipfslite'
2 |
--------------------------------------------------------------------------------