├── LICENSE ├── configure ├── configure.win ├── .gitignore ├── .Rbuildignore ├── NAMESPACE ├── ipfs.Rproj ├── DESCRIPTION ├── R ├── onload.R ├── ipns.R ├── daemon.R └── ipfs.R ├── man ├── daemon.Rd ├── ipns.Rd └── ipfs.Rd ├── .travis.yml ├── appveyor.yml ├── tools └── download_ipfs.R └── readme.md /LICENSE: -------------------------------------------------------------------------------- 1 | YEAR: 2016 2 | COPYRIGHT HOLDER: Your name goes here 3 | -------------------------------------------------------------------------------- /configure: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | ${R_HOME}/bin/Rscript --vanilla tools/download_ipfs.R 3 | exit 0 4 | -------------------------------------------------------------------------------- /configure.win: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | ${R_HOME}/bin/Rscript --vanilla tools/download_ipfs.R 3 | exit 0 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .Rproj.user 2 | .Rhistory 3 | inst 4 | readme.html 5 | tests/testthat/*.html 6 | ipfs.draft3.pdf 7 | -------------------------------------------------------------------------------- /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^.*\.Rproj$ 2 | ^\.Rproj\.user$ 3 | readme.md 4 | ipfs.draft3.pdf 5 | ^inst$ 6 | ^\.travis\.yml$ 7 | ^appveyor\.yml$ 8 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | export(ipfs_add) 4 | export(ipfs_browse) 5 | export(ipfs_cat) 6 | export(ipfs_commands) 7 | export(ipfs_config) 8 | export(ipfs_daemon) 9 | export(ipfs_data) 10 | export(ipfs_download) 11 | export(ipfs_get) 12 | export(ipfs_info) 13 | export(ipfs_ls) 14 | export(ipfs_publish) 15 | export(ipfs_resolve) 16 | export(ipfs_server) 17 | export(ipfs_stats) 18 | export(ipfs_swarm) 19 | export(ipfs_webui) 20 | -------------------------------------------------------------------------------- /ipfs.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: Default 4 | SaveWorkspace: Default 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: pdfLaTeX 14 | 15 | AutoAppendNewline: Yes 16 | StripTrailingWhitespace: Yes 17 | 18 | BuildType: Package 19 | PackageUseDevtools: Yes 20 | PackageInstallArgs: --no-multiarch --with-keep.source 21 | PackageRoxygenize: rd,namespace 22 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: ipfs 2 | Type: Package 3 | Title: Connect to the Inter Planetary File System 4 | Version: 0.1 5 | Author: Jeroen Ooms 6 | Maintainer: Jeroen Ooms 7 | Description: IPFS is a content-addressable, peer-to-peer hypermedia distribution 8 | protocol in which the nodes form a distributed file system. 9 | License: MIT + file LICENSE 10 | Encoding: UTF-8 11 | LazyData: true 12 | RoxygenNote: 6.0.1 13 | Remotes: jeroenooms/sys 14 | Imports: curl, jsonlite, sys (>= 1.1) 15 | -------------------------------------------------------------------------------- /R/onload.R: -------------------------------------------------------------------------------- 1 | .onAttach <- function(libname, pkgname){ 2 | if(ipfs_is_online()){ 3 | packageStartupMessage("ipfs deamon is running!") 4 | } else { 5 | ipfsdir <- file.path(libname, pkgname, "bin", "go-ipfs") 6 | if(file.exists(ipfsdir)){ 7 | path <- Sys.getenv("PATH") 8 | sep <- ifelse(identical(.Platform$OS.type, "windows"), ";", ":") 9 | Sys.setenv(PATH = paste(path, normalizePath(ipfsdir), sep = sep)) 10 | } 11 | if(has_ipfs()){ 12 | packageStartupMessage("Use ipfs_daemon() to start the IPFS server!") 13 | } else { 14 | packageStartupMessage("Main 'ipfs' executable not found :(") 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /man/daemon.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/daemon.R 3 | \name{ipfs_daemon} 4 | \alias{ipfs_daemon} 5 | \title{IPFS daemon} 6 | \usage{ 7 | ipfs_daemon(background = TRUE, silent = FALSE) 8 | } 9 | \arguments{ 10 | \item{background}{run the daemon as a background process (default). If set 11 | to `FALSE`, the server will block the current R session and print server 12 | output to the console. In this case you should use the client from a 13 | separate R sesssion. Useful for debugging.} 14 | 15 | \item{silent}{suppress server output} 16 | } 17 | \description{ 18 | Start and stop the ipfs server. This is automatically done when attaching 19 | the package. 20 | } 21 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: r 2 | cache: packages 3 | 4 | matrix: 5 | include: 6 | - os: linux 7 | dist: precise 8 | - os: linux 9 | dist: trusty 10 | sudo: required 11 | - os: osx 12 | latex: false 13 | osx_image: xcode8.1 14 | brew_packages: ipfs 15 | - os: osx 16 | latex: false 17 | osx_image: xcode8.1 18 | - os: osx 19 | latex: false 20 | osx_image: beta-xcode6.4 21 | 22 | r_github_packages: 23 | - jeroenooms/sys 24 | - jimhester/covr 25 | 26 | warnings_are_errors: true 27 | #r_check_revdep: true 28 | 29 | notifications: 30 | email: 31 | on_success: change 32 | on_failure: change 33 | 34 | after_success: 35 | - if [[ "${R_CODECOV}" ]]; then R -e 'covr::codecov()'; fi 36 | 37 | # Prevents Travis timeout for building magick 38 | before_install: 39 | - (while true; do echo 'Ping? Pong!'; sleep 500; done) & 40 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | # DO NOT CHANGE the "init" and "install" sections below 2 | 3 | # Download script file from GitHub 4 | init: 5 | ps: | 6 | $ErrorActionPreference = "Stop" 7 | Invoke-WebRequest http://raw.github.com/krlmlr/r-appveyor/master/scripts/appveyor-tool.ps1 -OutFile "..\appveyor-tool.ps1" 8 | Import-Module '..\appveyor-tool.ps1' 9 | 10 | install: 11 | ps: Bootstrap 12 | 13 | # Adapt as necessary starting from here 14 | 15 | environment: 16 | global: 17 | USE_RTOOLS: true 18 | 19 | build_script: 20 | - travis-tool.sh install_deps 21 | 22 | test_script: 23 | - travis-tool.sh run_tests 24 | 25 | on_failure: 26 | - 7z a failure.zip *.Rcheck\* 27 | - appveyor PushArtifact failure.zip 28 | 29 | artifacts: 30 | - path: '*.Rcheck\**\*.log' 31 | name: Logs 32 | 33 | - path: '*.Rcheck\**\*.out' 34 | name: Logs 35 | 36 | - path: '*.Rcheck\**\*.fail' 37 | name: Logs 38 | 39 | - path: '*.Rcheck\**\*.Rout' 40 | name: Logs 41 | 42 | - path: '\*_*.tar.gz' 43 | name: Bits 44 | 45 | - path: '\*_*.zip' 46 | name: Bits 47 | -------------------------------------------------------------------------------- /tools/download_ipfs.R: -------------------------------------------------------------------------------- 1 | # Downloads the 'ipfs' utility from: https://ipfs.io/docs/install 2 | # Supports Linux, OSX and Windows 3 | if(file.exists("inst/bin/go-ipfs/ipfs") || file.exists("inst/bin/go-ipfs/ipfs.exe")){ 4 | quit("no") 5 | } 6 | 7 | # Find binaries for your system 8 | platform <- sessionInfo()$platform 9 | 10 | # Case of Windows 11 | if(grepl("mingw", platform, ignore.case = TRUE)){ 12 | if(getRversion() < "3.3.0") setInternet2() 13 | download.file("https://dist.ipfs.io/go-ipfs/v0.4.7/go-ipfs_v0.4.7_windows-386.zip", "ipfs.zip") 14 | dir.create("inst/bin", showWarnings = FALSE, recursive = TRUE) 15 | unzip("ipfs.zip",files = "go-ipfs/ipfs.exe", exdir = "inst/bin") 16 | unlink("ipfs.zip") 17 | quit("no") 18 | } 19 | 20 | url <- if(grepl("x86_64.*darwin", platform, ignore.case = TRUE)){ 21 | "https://dist.ipfs.io/go-ipfs/v0.4.7/go-ipfs_v0.4.7_darwin-amd64.tar.gz" 22 | } else if(grepl("x86_64.*linux", platform, ignore.case = TRUE)){ 23 | "https://dist.ipfs.io/go-ipfs/v0.4.7/go-ipfs_v0.4.7_linux-amd64.tar.gz" 24 | } else if(grepl("freebsd", platform, ignore.case = TRUE)){ 25 | "https://dist.ipfs.io/go-ipfs/v0.4.7/go-ipfs_v0.4.7_freebsd-amd64.tar.gz" 26 | } else { 27 | cat("Unknown platform!") 28 | quit("no") 29 | } 30 | 31 | download.file(url, "ipfs.tar.gz") 32 | dir.create("inst/bin", showWarnings = FALSE, recursive = TRUE) 33 | untar("ipfs.tar.gz", files = "go-ipfs/ipfs", exdir = "inst/bin") 34 | unlink("ipfs.tar.gz") 35 | -------------------------------------------------------------------------------- /man/ipns.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ipns.R 3 | \name{ipns} 4 | \alias{ipns} 5 | \alias{ipfs_resolve} 6 | \alias{ipfs_publish} 7 | \title{IPNS name} 8 | \usage{ 9 | ipfs_resolve(name = NULL, recursive = FALSE, nocache = FALSE) 10 | 11 | ipfs_publish(path, lifetime = "24h") 12 | } 13 | \arguments{ 14 | \item{name}{the IPNS name (owner) to resolve. Defaults to your own name} 15 | 16 | \item{recursive}{resolve until the result is not an IPNS name} 17 | 18 | \item{nocache}{do not use cached entries} 19 | 20 | \item{path}{IPFS path of the object to be published under your name} 21 | 22 | \item{lifetime}{Time duration that the record will be valid for. This accepts 23 | durations such as "300s", "1.5h" or "2h45m".} 24 | } 25 | \description{ 26 | IPNS is a PKI namespace, where names are the hashes of public keys, and 27 | the private key enables publishing new (signed) values. In publish, the 28 | default value of is your own identity public key. 29 | } 30 | \examples{ 31 | # Publish a file! 32 | writeLines("Hi there!", tmp <- tempfile()) 33 | out <- ipfs_add(tmp) 34 | ipfs_browse(out$hash) 35 | 36 | # Link your name to this file 37 | ipfs_publish(out$hash) 38 | 39 | # Resolve back via your name 40 | me <- ipfs_info()$ID 41 | doc <- ipfs_resolve(me) 42 | ipfs_cat(doc) 43 | 44 | # Resolve other people 45 | ipfs_resolve("QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ") 46 | ipfs_resolve('ipfs.io') 47 | } 48 | \references{ 49 | \url{https://github.com/ipfs/examples/tree/master/examples/ipns#readme} 50 | } 51 | -------------------------------------------------------------------------------- /R/ipns.R: -------------------------------------------------------------------------------- 1 | #' IPNS name 2 | #' 3 | #' IPNS is a PKI namespace, where names are the hashes of public keys, and 4 | #' the private key enables publishing new (signed) values. In publish, the 5 | #' default value of is your own identity public key. 6 | #' 7 | #' @export 8 | #' @name ipns 9 | #' @rdname ipns 10 | #' @references \url{https://github.com/ipfs/examples/tree/master/examples/ipns#readme} 11 | #' @param name the IPNS name (owner) to resolve. Defaults to your own name 12 | #' @param recursive resolve until the result is not an IPNS name 13 | #' @param nocache do not use cached entries 14 | #' @examples # Publish a file! 15 | #' writeLines("Hi there!", tmp <- tempfile()) 16 | #' out <- ipfs_add(tmp) 17 | #' ipfs_browse(out$hash) 18 | #' 19 | #' # Link your name to this file 20 | #' ipfs_publish(out$hash) 21 | #' 22 | #' # Resolve back via your name 23 | #' me <- ipfs_info()$ID 24 | #' doc <- ipfs_resolve(me) 25 | #' ipfs_cat(doc) 26 | #' 27 | #' # Resolve other people 28 | #' ipfs_resolve("QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ") 29 | #' ipfs_resolve('ipfs.io') 30 | ipfs_resolve <- function(name = NULL, recursive = FALSE, nocache = FALSE){ 31 | out <- if(is.null(name)){ 32 | ipfs_json("name/resolve", recursive = recursive, nocache = nocache) 33 | } else { 34 | ipfs_json("name/resolve", arg = name, recursive = recursive, nocache = nocache) 35 | } 36 | out$Path 37 | } 38 | 39 | #' @export 40 | #' @rdname ipns 41 | #' @param path IPFS path of the object to be published under your name 42 | #' @param lifetime Time duration that the record will be valid for. This accepts 43 | #' durations such as "300s", "1.5h" or "2h45m". 44 | ipfs_publish <- function(path, lifetime = "24h"){ 45 | ipfs_json("name/publish", arg = path, lifetime = lifetime) 46 | } 47 | -------------------------------------------------------------------------------- /man/ipfs.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ipfs.R 3 | \name{ipfs} 4 | \alias{ipfs} 5 | \alias{ipfs_get} 6 | \alias{ipfs_add} 7 | \alias{ipfs_ls} 8 | \alias{ipfs_data} 9 | \alias{ipfs_cat} 10 | \alias{ipfs_swarm} 11 | \alias{ipfs_stats} 12 | \alias{ipfs_download} 13 | \alias{ipfs_info} 14 | \alias{ipfs_config} 15 | \alias{ipfs_browse} 16 | \alias{ipfs_webui} 17 | \alias{ipfs_commands} 18 | \alias{ipfs_server} 19 | \title{IPFS} 20 | \usage{ 21 | ipfs_get(key) 22 | 23 | ipfs_add(files) 24 | 25 | ipfs_ls(key) 26 | 27 | ipfs_data(key) 28 | 29 | ipfs_cat(key) 30 | 31 | ipfs_swarm() 32 | 33 | ipfs_stats() 34 | 35 | ipfs_download(key, path = NULL) 36 | 37 | ipfs_info() 38 | 39 | ipfs_config() 40 | 41 | ipfs_browse(key, gateway = "https://ipfs.io/ipfs/") 42 | 43 | ipfs_webui() 44 | 45 | ipfs_commands() 46 | 47 | ipfs_server(new_url = NULL) 48 | } 49 | \arguments{ 50 | \item{key}{a multihash key} 51 | 52 | \item{files}{path(s) of files to add} 53 | 54 | \item{path}{filename to save download.} 55 | 56 | \item{gateway}{any IPFS gateway server} 57 | 58 | \item{new_url}{set a different API server. Default is "http://127.0.0.1:5001"} 59 | } 60 | \description{ 61 | Connect to the inter-planetary file system. 62 | } 63 | \examples{ 64 | # From 'getting started' 65 | ipfs_daemon(TRUE) 66 | ipfs_info() 67 | ipfs_get('QmYwAPJzv5CZsnA625s3Xf2nemtYgPpHdWEz79ojWnPbdG') 68 | ipfs_data('QmYwAPJzv5CZsnA625s3Xf2nemtYgPpHdWEz79ojWnPbdG/readme') 69 | ipfs_download('QmR7GSQM93Cx5eAg6a6yRzNde1FQv7uL6X1o4k7zrJa3LX/ipfs.draft3.pdf') 70 | # utils::browseURL('ipfs.draft3.pdf') 71 | } 72 | \references{ 73 | IPFS api: \url{https://ipfs.io/docs/api/} 74 | Draft paper: \url{https://ipfs.io/ipfs/QmR7GSQM93Cx5eAg6a6yRzNde1FQv7uL6X1o4k7zrJa3LX/ipfs.draft3.pdf} 75 | } 76 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # IPFS 2 | 3 | > Connect to the Inter Planetary File System 4 | 5 | [![Build Status](https://travis-ci.org/jeroen/ipfs.svg?branch=master)](https://travis-ci.org/jeroen/ipfs) 6 | [![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/jeroen/ipfs?branch=master&svg=true)](https://ci.appveyor.com/project/jeroen/ipfs) 7 | [![Coverage Status](https://codecov.io/github/jeroen/ipfs/coverage.svg?branch=master)](https://codecov.io/github/jeroen/ipfs?branch=master) 8 | [![CRAN_Status_Badge](http://www.r-pkg.org/badges/version/ipfs)](http://cran.r-project.org/package=ipfs) 9 | [![CRAN RStudio mirror downloads](http://cranlogs.r-pkg.org/badges/ipfs)](http://cran.r-project.org/web/packages/ipfs/index.html) 10 | [![Github Stars](https://img.shields.io/github/stars/jeroen/ipfs.svg?style=social&label=Github)](https://github.com/jeroen/ipfs) 11 | 12 | ## Installation 13 | 14 | Install from Github: 15 | 16 | ```r 17 | devtools::install_github("jeroenooms/ipfs") 18 | ``` 19 | 20 | The installer should automatically download the `ipfs` program. 21 | 22 | ## Getting Started 23 | 24 | First start the `ipfs` server daemon 25 | 26 | ```r 27 | # Start the server in the background 28 | ipfs_daemon() 29 | 30 | # Check server status: 31 | ipfs_info() 32 | ``` 33 | 34 | You are now connected to the inter-planetary file system! Download some files: 35 | 36 | ```r 37 | ipfs_get('QmYwAPJzv5CZsnA625s3Xf2nemtYgPpHdWEz79ojWnPbdG') 38 | ipfs_cat('QmYwAPJzv5CZsnA625s3Xf2nemtYgPpHdWEz79ojWnPbdG/readme') 39 | ipfs_download('QmR7GSQM93Cx5eAg6a6yRzNde1FQv7uL6X1o4k7zrJa3LX/ipfs.draft3.pdf') 40 | utils::browseURL('ipfs.draft3.pdf') 41 | ``` 42 | 43 | Or publish a file of your own! 44 | 45 | ```r 46 | # Publish a file! 47 | writeLines("Hi there!", tmp <- tempfile()) 48 | out <- ipfs_add(tmp) 49 | ipfs_browse(out$hash) 50 | ``` 51 | 52 | See the `?ipfs` and `?ipns` help pages for more information. 53 | -------------------------------------------------------------------------------- /R/daemon.R: -------------------------------------------------------------------------------- 1 | daemon <- local({ 2 | pid <- NULL 3 | ipfs_start <- function(background = TRUE, silent = FALSE){ 4 | ipfs_stop() 5 | if(identical(background, FALSE)){ 6 | message("Running ipfs in foreground. Press ESC or CTRL+C to stop") 7 | return(sys::exec_wait("ipfs", c("daemon", "--init"), std_out = !silent, std_err = !silent)) 8 | } 9 | message("Starting IPFS. Give it a few seconds...") 10 | bg <- sys::exec_background("ipfs", c("daemon", "--init"), std_out = !silent, std_err = !silent) 11 | pid <<- as.numeric(bg) # drops: attr(pid, "handle") 12 | gc() 13 | reg.finalizer(environment(.onAttach), function(x){ 14 | ipfs_stop() 15 | }, onexit = TRUE) 16 | while(!ipfs_is_online()){ 17 | Sys.sleep(1) 18 | } 19 | cat("OK!\n") 20 | invisible() 21 | } 22 | 23 | ipfs_stop <- function(){ 24 | if(!is.null(pid)){ 25 | cat("stopping ipfs...\n") 26 | tools::pskill(pid) 27 | pid <<- NULL 28 | try(sys::exec_status(pid), silent = TRUE) 29 | } 30 | } 31 | environment() 32 | }) 33 | 34 | 35 | has_ipfs <- function(){ 36 | out <- try(sys::exec_wait('ipfs', '--version', std_out = FALSE), silent = TRUE) 37 | !inherits(out, "try-error") 38 | } 39 | 40 | ipfs_is_online <- function(){ 41 | url <- ipfs_api("version") 42 | handle <- curl::new_handle(TIMEOUT = 1, CONNECTTIMEOUT = 1) 43 | out <- try(curl::curl_fetch_memory(url), silent = TRUE) 44 | !inherits(out, "try-error") 45 | } 46 | 47 | 48 | #' IPFS daemon 49 | #' 50 | #' Start and stop the ipfs server. This is automatically done when attaching 51 | #' the package. 52 | #' 53 | #' @export 54 | #' @rdname daemon 55 | #' @param background run the daemon as a background process (default). If set 56 | #' to `FALSE`, the server will block the current R session and print server 57 | #' output to the console. In this case you should use the client from a 58 | #' separate R sesssion. Useful for debugging. 59 | #' @param silent suppress server output 60 | ipfs_daemon <- daemon$ipfs_start 61 | -------------------------------------------------------------------------------- /R/ipfs.R: -------------------------------------------------------------------------------- 1 | #' IPFS 2 | #' 3 | #' Connect to the inter-planetary file system. 4 | #' 5 | #' @export 6 | #' @name ipfs 7 | #' @rdname ipfs 8 | #' @param key a multihash key 9 | #' @references IPFS api: \url{https://ipfs.io/docs/api/} 10 | #' Draft paper: \url{https://ipfs.io/ipfs/QmR7GSQM93Cx5eAg6a6yRzNde1FQv7uL6X1o4k7zrJa3LX/ipfs.draft3.pdf} 11 | #' @examples # From 'getting started' 12 | #' ipfs_daemon(TRUE) 13 | #' ipfs_info() 14 | #' ipfs_get('QmYwAPJzv5CZsnA625s3Xf2nemtYgPpHdWEz79ojWnPbdG') 15 | #' ipfs_data('QmYwAPJzv5CZsnA625s3Xf2nemtYgPpHdWEz79ojWnPbdG/readme') 16 | ipfs_get <- function(key){ 17 | ipfs_json("object/get", arg = key) 18 | } 19 | 20 | #' @export 21 | #' @rdname ipfs 22 | #' @param files path(s) of files to add 23 | ipfs_add <- function(files){ 24 | post <- lapply(files, function(x){ 25 | curl::form_file(normalizePath(x, mustWork = TRUE)) 26 | }) 27 | names(post) <- basename(files) 28 | data <- ipfs_raw("add", post = post) 29 | con <- rawConnection(data) 30 | on.exit(close(con)) 31 | df <- jsonlite::stream_in(con, verbose = FALSE) 32 | names(df) <- tolower(names(df)) 33 | df 34 | } 35 | 36 | #' @export 37 | #' @rdname ipfs 38 | ipfs_ls <- function(key){ 39 | ipfs_json("ls", arg = key) 40 | } 41 | 42 | #' @export 43 | #' @rdname ipfs 44 | ipfs_data <- function(key){ 45 | buf <- ipfs_raw("object/data", arg = key) 46 | if(identical(buf, as.raw(c(0x08, 0x01)))) 47 | stop("Not a data block") 48 | return(buf) 49 | } 50 | 51 | #' @export 52 | #' @rdname ipfs 53 | ipfs_cat <- function(key){ 54 | buf <- ipfs_data(key) 55 | cat(rawToChar(buf)) 56 | invisible(buf) 57 | } 58 | 59 | #' @export 60 | #' @rdname ipfs 61 | ipfs_swarm <- function(){ 62 | list( 63 | local = ipfs_json("swarm/addrs/local")$Strings, 64 | peers = ipfs_json("swarm/peers")$Strings 65 | ) 66 | } 67 | 68 | #' @export 69 | #' @rdname ipfs 70 | ipfs_stats <- function(){ 71 | list( 72 | bitswap = ipfs_json("stats/bitswap"), 73 | repo = ipfs_json("stats/repo"), 74 | bw = ipfs_json("stats/bw") 75 | ) 76 | } 77 | 78 | #' @export 79 | #' @rdname ipfs 80 | #' @param path filename to save download. 81 | #' @examples ipfs_download('QmR7GSQM93Cx5eAg6a6yRzNde1FQv7uL6X1o4k7zrJa3LX/ipfs.draft3.pdf') 82 | #' # utils::browseURL('ipfs.draft3.pdf') 83 | ipfs_download <- function(key, path = NULL){ 84 | if(!length(path)) 85 | path <- basename(key) 86 | buf <- ipfs_data(key) 87 | writeBin(buf, path) 88 | return(path) 89 | } 90 | 91 | #' @export 92 | #' @rdname ipfs 93 | ipfs_info <- function(){ 94 | version <- ipfs_json("version") 95 | id <- ipfs_json("id") 96 | c(id, version) 97 | } 98 | 99 | #' @export 100 | #' @rdname ipfs 101 | ipfs_config <- function(){ 102 | ipfs_json("config/show") 103 | } 104 | 105 | #' @export 106 | #' @rdname ipfs 107 | #' @param gateway any IPFS gateway server 108 | ipfs_browse <- function(key, gateway = "https://ipfs.io/ipfs/"){ 109 | url <- paste0(gateway, key) 110 | utils::browseURL(url) 111 | return(url) 112 | } 113 | 114 | #' @export 115 | #' @rdname ipfs 116 | ipfs_webui <- function(){ 117 | ipfs_info() #check that demon is online 118 | utils::browseURL(ipfs_api("webui")) 119 | } 120 | 121 | #' @export 122 | #' @rdname ipfs 123 | ipfs_commands <- function(){ 124 | print_tree <- function(x, indent){ 125 | opts <- unlist(sapply(x$Options, function(y){y$Names[[1]]})) 126 | optstr <- ifelse(length(opts), paste("[", paste0("--", opts, collapse = ", "), "]"), " ") 127 | cat(sprintf("%s- %s %s\n", strrep(' ', indent), x$Name, optstr)) 128 | lapply(x$Subcommands, print_tree, indent = indent + 2) 129 | } 130 | buf <- ipfs_raw("commands", enc = "json") 131 | data <- jsonlite::fromJSON(rawToChar(buf), simplifyVector = FALSE) 132 | invisible(lapply(data[[2]], print_tree, indent = 2)) 133 | } 134 | 135 | ipfs_raw <- function(command, ..., post = NULL){ 136 | params <- list(...) 137 | ipfs_fetch(command, params, post) 138 | } 139 | 140 | ipfs_json <- function(command, ...){ 141 | data <- ipfs_raw(command, enc = "json", ...) 142 | jsonlite::fromJSON(rawToChar(data)) 143 | } 144 | 145 | ipfs_fetch <- function(command, params, post = NULL){ 146 | url <- ipfs_api("api/v0", command) 147 | h <- curl::new_handle() 148 | if(length(params)){ 149 | str <- paste(names(params), as.character(params), collapse = "&", sep = "=") 150 | url <- paste(url, str, sep = "?") 151 | } 152 | if(length(post)){ 153 | curl::handle_setform(h, .list = as.list(post)) 154 | } 155 | req <- curl::curl_fetch_memory(url, handle = h) 156 | if(req$status_code >= 400) 157 | stop(sprintf("HTTP %s", rawToChar(req$content)), call. = FALSE) 158 | req$content 159 | } 160 | 161 | 162 | #' @export 163 | #' @rdname ipfs 164 | #' @param new_url set a different API server. Default is "http://127.0.0.1:5001" 165 | ipfs_server <- local({ 166 | provider_url <- "http://127.0.0.1:5001" 167 | function(new_url = NULL){ 168 | if(length(new_url)){ 169 | new_url <- sub("/$", "", new_url) 170 | req <- curl::curl_fetch_memory(paste0(new_url, "/api/v0/version")) 171 | if(req$status_code != 200) 172 | stop(sprintf("Failed to connect (HTTP %d)", req$status_code), call. = FALSE) 173 | provider_url <<- new_url 174 | } 175 | return(provider_url) 176 | } 177 | }) 178 | 179 | ipfs_api <- function(...){ 180 | paste(ipfs_server(), ..., sep = "/") 181 | } 182 | --------------------------------------------------------------------------------