Skip to content

ipfs支持 #437

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions ipfs_run.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# IPFS 节点搭建

## 下载安装

```shell
wget https://dist.ipfs.io/kubo/v0.14.0/kubo_v0.14.0_linux-amd64.tar.gz -O ./go-ipfs_linux-amd64.tar.gz
tar -xvf ./go-ipfs_linux-amd64.tar.gz
```

## 初始化
zfile 需要和Ipfs节点搭建在同一机器上

在zfile的存储源设置中设置网关为http://ip:8082
```shell
export PATH=$PATH:$PWD/go-ipfs/
ipfs init
# zfile使用8080端口,所以将ipfs端口改为8082
# 将127.0.0.1 修改为 监听的ip 一般需要对外提供服务的需要设置为 0.0.0.0 或公网ip
ipfs config Addresses.Gateway /ip4/127.0.0.1/tcp/8082
```

## 启动,需添加进程守护

```shell
ipfs daemon
```
可以使用
```shell
ipfs daemon &
```
16 changes: 16 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@
<org.mapstruct.version>1.5.1.Final</org.mapstruct.version>
</properties>

<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>

<dependencies>
<!-- spring boot 官方相关 -->
<dependency>
Expand Down Expand Up @@ -94,6 +101,15 @@
<artifactId>jsch</artifactId>
<version>0.1.55</version>
</dependency>

<dependency>
<groupId>com.github.ipfs</groupId>
<artifactId>java-ipfs-http-client</artifactId>
<version>1.3.3</version>
</dependency>


<!-- 其他工具类 -->
<dependency>
<groupId>com.github.lookfirst</groupId>
<artifactId>sardine</artifactId>
Expand Down
26 changes: 26 additions & 0 deletions src/main/java/im/zhaojun/zfile/admin/model/param/IpfsParam.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package im.zhaojun.zfile.admin.model.param;

import im.zhaojun.zfile.admin.annoation.StorageParamItem;
import im.zhaojun.zfile.admin.model.enums.StorageParamTypeEnum;
import lombok.Getter;

/**
* 本地存储初始化参数
*
* @author zhaojun
*/
@Getter
public class IpfsParam extends ProxyDownloadParam {

@StorageParamItem(name = "服务器地址",
defaultValue = "/ip4/127.0.0.1/tcp/5001",
description = "IPFS服务器API接口")
private String apiAddr;

@StorageParamItem(name = "使用网关", type = StorageParamTypeEnum.SWITCH, defaultValue = "true", description = "默认使用ipfs网关,关闭后使用ipfs://协议头)")
private boolean isPrivate;

@StorageParamItem(name = "ipfs网关", required = false, description = "如不配置网关,则使用公用网关, 反之则使用指定网关下载.")
private String domain;

}
4 changes: 4 additions & 0 deletions src/main/java/im/zhaojun/zfile/common/util/HttpUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.io.OutputStream;
import java.net.URL;
import java.net.URLConnection;

Expand Down Expand Up @@ -43,6 +44,9 @@ public static String getTextContent(String url) {

return result == null ? "" : result;
}
public static Long downloadFile(String url, OutputStream outputStream){
return cn.hutool.http.HttpUtil.download(url,outputStream,true);
}


/**
Expand Down
116 changes: 116 additions & 0 deletions src/main/java/im/zhaojun/zfile/common/util/IpfsHelper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package im.zhaojun.zfile.common.util;

import io.ipfs.api.IPFS;
import io.ipfs.api.MerkleNode;
import io.ipfs.api.NamedStreamable;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;

/**
* IPFS 库的扩展
*
* @author wswm152
*/
public class IpfsHelper {
/**
* ipfs 实例
*/
private final IPFS ipfs;
/**
* 从IPFS库反射的方法
*/
private final Method m_retrieveMap, m_retrieve;

public final IPFS.File file;
/**
* IPFS库的扩展实现,不是标准的接口实现
*/
public final Files files = new Files();


public IpfsHelper(String apiAddr) {

IPFS ipfs = new IPFS(apiAddr);
this.ipfs = ipfs;
file = ipfs.file;


try {
//私有函数的反射
Class<?> ipfs_p = Class.forName("io.ipfs.api.IPFS");
m_retrieveMap = ipfs_p.getDeclaredMethod("retrieveMap", String.class);
m_retrieveMap.setAccessible(true);
m_retrieve = ipfs_p.getDeclaredMethod("retrieve", String.class);
m_retrieve.setAccessible(true);
} catch (ClassNotFoundException | NoSuchMethodException e) {
throw new RuntimeException(e);
}
}

public class Files {
public Map ls(String path) throws IOException {
return retrieveMap("files/ls?arg=" + path);
}

public Map stat(String path) throws IOException {
return retrieveMap("files/stat?arg=" + path);
}

public String mkdir(String path) throws IOException {
return new String(retrieve("files/mkdir?arg=" + path + "&parents=true"));
}

public String rm(String path) throws IOException {
return new String(retrieve("files/rm?arg=" + path + "&recursive=true"));
}

public String mv(String source, String dest) throws IOException {
return new String(retrieve("files/mv?arg=" + source + "&arg=" + dest));
}

public String cp(String source, String dest) throws IOException {
return new String(retrieve("files/cp?arg=" + source + "&arg=" + dest));
}

public String upload(InputStream stream, String dest) throws IOException {
NamedStreamable.InputStreamWrapper inputsteam = new NamedStreamable.InputStreamWrapper(stream);
String hash = add(inputsteam).get(0).hash.toString();
return cp("/ipfs/".concat(hash), dest);
}

public Long download(String path, OutputStream outputStream) {
return HttpUtil.downloadFile(path,outputStream);
}
}

public List<MerkleNode> add(NamedStreamable file) throws IOException {
return ipfs.add(file);
}

private Map retrieveMap(String path) throws IOException {
try {
return (Map) m_retrieveMap.invoke(ipfs, path);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw (IOException) e.getTargetException();
}
}

private byte[] retrieve(String path) throws IOException {
try {
return (byte[]) m_retrieve.invoke(ipfs, path);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw (IOException) e.getTargetException();
}
}
}

25 changes: 23 additions & 2 deletions src/main/java/im/zhaojun/zfile/common/util/StringUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public class StringUtils {

public static final String HTTPS_PROTOCOL = "https://";


public static final String IPFS_PROTOCOL = "ipfs://";
/**
* 移除 URL 中的前后的所有 '/'
*
Expand Down Expand Up @@ -106,7 +106,7 @@ public static String removeDuplicateSlashes(String path) {
StringBuilder sb = new StringBuilder();

// 是否包含 http 或 https 协议信息
boolean containProtocol = StrUtil.containsAnyIgnoreCase(path, HTTP_PROTOCOL, HTTPS_PROTOCOL);
boolean containProtocol = StrUtil.containsAnyIgnoreCase(path, HTTP_PROTOCOL, HTTPS_PROTOCOL,IPFS_PROTOCOL);

if (containProtocol) {
path = trimStartSlashes(path);
Expand All @@ -116,11 +116,15 @@ public static String removeDuplicateSlashes(String path) {
boolean startWithHttpProtocol = StrUtil.startWithIgnoreCase(path, HTTP_PROTOCOL);
// 是否包含 https 协议信息
boolean startWithHttpsProtocol = StrUtil.startWithIgnoreCase(path, HTTPS_PROTOCOL);
// 是否包含 ipfs 协议信息
boolean startWithIpfsProtocol = StrUtil.startWithIgnoreCase(path, IPFS_PROTOCOL);

if (startWithHttpProtocol) {
sb.append(HTTP_PROTOCOL);
} else if (startWithHttpsProtocol) {
sb.append(HTTPS_PROTOCOL);
} else if (startWithIpfsProtocol) {
sb.append(IPFS_PROTOCOL);
}

for (int i = sb.length(); i < path.length() - 1; i++) {
Expand Down Expand Up @@ -393,6 +397,23 @@ public static String getParentPath(String path) {
return StrUtil.sub(path, 0, toIndex);
}
}
/**
* 获取文件或文件夹名字
*
* @param path
* 文件路径
*
* @return 文件名
*/
public static String getFileName(String path) {
path = StringUtils.trimEndSlashes(path);
int fromIndex = StrUtil.lastIndexOfIgnoreCase(path, ZFileConstant.PATH_SEPARATOR);
if (fromIndex < 0) {
return "";
} else {
return StrUtil.sub(path, fromIndex+1, path.length());
}
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public enum StorageTypeEnum implements IEnum {
* 当前系统支持的所有存储源类型
*/
LOCAL("local", "本地存储"),
IPFS("ipfs","ipfs"),
ALIYUN("aliyun", "阿里云 OSS"),
WEBDAV("webdav", "WebDAV"),
TENCENT("tencent", "腾讯云 COS"),
Expand Down
Loading