Skip to content

Commit 745aa43

Browse files
committed
v3: update all dependencies, clean up code
1 parent e424b02 commit 745aa43

File tree

20 files changed

+1286
-1146
lines changed

20 files changed

+1286
-1146
lines changed

LICENSE

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
Copyright 2025 Haku Labs MTÜ
2+
3+
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
4+
5+
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
6+
7+
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
8+
9+
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
10+
11+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Makefile

Lines changed: 56 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,61 @@
1-
.PHONY: default build fmt lint run run_race test clean vet docker_build docker_run docker_clean
1+
.PHONY: default build clean
22

3+
VERSION := 3.0.0
34
LIB_NAME := libipfs
5+
SRC := ./${LIB_NAME}.go
6+
BIN_DIR := bin
7+
8+
PLATFORMS := \
9+
linux/amd64 \
10+
freebsd/amd64 \
11+
windows/amd64 \
12+
darwin/amd64 \
13+
darwin/arm64 \
14+
linux/riscv64 \
15+
linux/arm64
16+
17+
# Define cross-compilers for each architecture
18+
CC_COMPILERS := \
19+
freebsd/amd64=clang --target=x86_64-unknown-freebsd \
20+
windows/amd64=x86_64-w64-mingw32-gcc \
21+
linux/amd64=gcc \
22+
linux/arm64=aarch64-linux-gnu-gcc \
23+
linux/riscv64=riscv64-linux-gnu-gcc \
24+
darwin/amd64=o64-clang \
25+
darwin/arm64=o64-clang
26+
27+
# Default target
428
default: build
529

30+
# Clean target
631
clean:
7-
rm -rf bin/ && mkdir bin/
8-
9-
build_linux_x64:
10-
CGO_ENABLED=1 \
11-
GOOS=linux \
12-
GOARCH=amd64 \
13-
go build -buildmode=c-archive -o ./bin/${LIB_NAME}-linux.a ./src/${LIB_NAME}.go
14-
15-
build_linux_arm64:
16-
CGO_ENABLED=1 \
17-
GOOS=linux \
18-
GOARCH=arm64 \
19-
go build -buildmode=c-archive -o ./bin/${LIB_NAME}-linux-arm64.a ./src/${LIB_NAME}.go
20-
21-
build_windows_x64:
22-
CGO_ENABLED=1 \
23-
GOOS=windows \
24-
GOARCH=amd64 \
25-
go build -buildmode=c-archive -o ./bin/${LIB_NAME}-windows.a ./src/${LIB_NAME}.go
26-
27-
build_linux_riscv:
28-
CGO_ENABLED=1 \
29-
GOOS=linux \
30-
GOARCH=riscv64 \
31-
go build -buildmode=c-archive -o ./bin/${LIB_NAME}-linux-riscv64.a ./src/${LIB_NAME}.go
32-
33-
build_darwin_x64:
34-
CGO_ENABLED=1 \
35-
GOOS=darwin \
36-
GOARCH=amd64 \
37-
go build -buildmode=c-archive -o ./bin/${LIB_NAME}-darwin.a ./src/${LIB_NAME}.go
38-
39-
build_darwin_arm64:
40-
CGO_ENABLED=1 \
41-
GOOS=darwin \
42-
GOARCH=arm64 \
43-
go build -buildmode=c-archive -o ./bin/${LIB_NAME}-darwin-arm64.a ./src/${LIB_NAME}.go
44-
45-
build_freebsd_x64:
46-
CGO_ENABLED=1 \
47-
GOOS=freebsd \
48-
GOARCH=amd64 \
49-
go build -buildmode=c-archive -o ./bin/${LIB_NAME}-freebsd.a ./src/${LIB_NAME}.go
50-
51-
build-all: build_linux_x64 build_linux_arm64 build_windows_x64 build_linux_riscv build_darwin_x64 build_darwin_arm64 build_freebsd_x64
52-
53-
build: clean \
54-
build-all
32+
rm -rf $(BIN_DIR)/ && mkdir -p $(BIN_DIR) && cp -rf example.cpp $(BIN_DIR)/
33+
34+
# Function to get the cross-compiler based on GOOS/GOARCH
35+
define GET_CC
36+
$(shell echo $(CC_COMPILERS) | tr ' ' '\n' | grep -E '$(1)/$(2)=' | cut -d= -f2)
37+
endef
38+
39+
# Build rule for each platform
40+
define BUILD_RULE
41+
build_$(1)_$(2):
42+
@echo "Building for $(1)/$(2)..."
43+
$(if $(filter $(1)/$(2),freebsd/amd64), \
44+
env SYSROOT=/usr/local/freebsd-sysroot CGO_CFLAGS="--sysroot=/usr/local/freebsd-sysroot" CGO_LDFLAGS="--sysroot=/usr/local/freebsd-sysroot",) \
45+
CGO_ENABLED=1 \
46+
GOOS=$(1) \
47+
GOARCH=$(2) \
48+
CC=$(call GET_CC,$(1),$(2)) \
49+
go build -buildmode=c-archive -o $(BIN_DIR)/${LIB_NAME}-$(1)-$(2).a $(SRC)
50+
.PHONY: build_$(1)_$(2)
51+
endef
52+
53+
# Generate build rules for all platforms
54+
$(foreach plat, $(PLATFORMS), \
55+
$(eval $(call BUILD_RULE,$(word 1,$(subst /, ,$(plat))),$(word 2,$(subst /, ,$(plat))))))
56+
57+
# Build all platforms
58+
build-all: $(foreach plat, $(PLATFORMS), build_$(subst /,_,$(plat)))
59+
60+
# Main build target
61+
build: clean build-all

README.md

Lines changed: 29 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,45 @@
11
# libIPFS
22

3-
A C-style library library that wraps around go-ipfs as a library(not an executable that is embedded) and provides a very simple API.
3+
`libIPFS` is a C-style library that wraps around `go-ipfs` as a library (not an embedded executable) and provides a simple and intuitive API.
44

5-
## Example
6-
7-
```cpp
8-
#include "libipfs-linux.h"
9-
#include <iostream>
10-
11-
int main() {
12-
std::cout << "Starting IPFS node" << std::endl;
13-
std::cout << IPFSStartNode((char*)"", 0) << std::endl;
14-
15-
std::cout << "Getting peer ID" << std::endl;
16-
std::cout << GetPeerID() << std::endl;
17-
18-
std::cout << "Adding file to IPFS" << std::endl;
19-
std::cout << IpfsAdd((char*)"./test-file.jpg") << std::endl;
20-
21-
std::cout << "Adding directory to IPFS" << std::endl;
22-
std::cout << IpfsAdd((char*)"./test-dir") <<std::endl;
23-
24-
std::cout << "Downloading file from IPFS" << std::endl;
25-
std::cout << IpfsGet((char*)"QmXL7PCYH8VtMxkVTPBXxpnpF893QrLHC5H5AKv2FaAExU", (char*)"./test-download.jpg") << std::endl;
26-
27-
std::cout << "Pinning file to IPFS" << std::endl;
28-
std::cout << IpfsPin((char*)"QmXL7PCYH8VtMxkVTPBXxpnpF893QrLHC5H5AKv2FaAExU") << std::endl;
29-
30-
std::cout << "Locally Pinned Hashes" << std::endl;
31-
std::cout << IpfsGetPinnedHashes() << std::endl;
32-
33-
std::cout << "Resolving /ipns/ipfs.io to IPFS hash" << std::endl;
34-
std::cout << ResolveIPNSName((char*)"/ipns/ipfs.io") << std::endl;
5+
## Building
356

36-
std::cout << "Publishing to IPNS" << std::endl;
37-
std::cout << PublishIPFSName((char*)"QmXL7PCYH8VtMxkVTPBXxpnpF893QrLHC5H5AKv2FaAExU") << std::endl;
7+
Use the provided `Makefile` to build the library. For example, to build for Linux on `amd64`:
388

39-
std::cout << "Stopping IPFS node" << std::endl;
40-
std::cout << IPFSStopNode() << std::endl;
41-
}
9+
```bash
10+
make build_linux_amd64
4211
```
4312

44-
## Overview
13+
You can also build for other platforms by specifying the target:
4514

46-
libIPFS is used by the Scala Network Project to retrieve and publish critical information on to IPFS.
15+
```bash
16+
make build_windows_amd64
17+
make build_darwin_amd64
18+
make build_darwin_arm64
19+
make build_linux_riscv64
20+
make build_linux_arm64
21+
make build_freebsd_amd64
22+
```
4723

48-
It runs a *barebones* IPFS instance and provides functions to be called from C/C++.
24+
> **Note:**
25+
> - Cross-compilation has been tested on Debian 12.
26+
> - For FreeBSD builds, you may need a proper sysroot configuration.
27+
> - For macOS builds, `osxcross` is required.
4928
50-
### Why?
29+
## Usage
5130

52-
Currently, no simple implementation or API exists for IPFS in C or C++. Instead of writing, or re-writing, large parts of IPFS in C or C++ we rather use Go and compile it to a C or C++ compatible library. IPFS is implemented in Go already.
31+
An example program, `example.cpp`, is provided in the root of the repository. After building the library, copy the example file to the `bin/` folder and compile it with `g++`:
5332

54-
## Building
33+
```bash
34+
g++ -pthread -o libipfs-example example.cpp libipfs-linux-amd64.a -Wl,--no-as-needed -ldl -lresolv
35+
```
5536

56-
### Requirements
37+
Run the compiled example:
5738

58-
* go >= 1.16
59-
* make >= 4.2.1
60-
* gcc and g++ >= 9.3.0
39+
```bash
40+
./libipfs-example
41+
```
6142

62-
To build the library you can use the following commands, the outputs can be found in bin/
43+
## License
6344

64-
```
65-
go mod download
66-
make build
67-
```
45+
This project is licensed under the terms specified in the [LICENSE](LICENSE) file.

example.cpp

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
#include "libipfs-linux-amd64.h"
2+
#include <unistd.h>
3+
#include <iostream>
4+
#include <nlohmann/json.hpp>
5+
6+
using json = nlohmann::json;
7+
8+
bool isStatusSuccess(const char* response) {
9+
try {
10+
json parsed = json::parse(response);
11+
return (parsed["Status"] == "success");
12+
} catch (const json::exception& e) {
13+
std::cerr << "JSON Parsing Error: " << e.what() << std::endl;
14+
return false;
15+
}
16+
}
17+
18+
void handleResponse(bool success, const std::string& successMsg, const std::string& errorMsg, const char* response = nullptr) {
19+
if (success) {
20+
std::cout << successMsg << std::endl;
21+
} else {
22+
std::cerr << errorMsg << std::endl;
23+
if (response) {
24+
std::cerr << response << std::endl;
25+
}
26+
}
27+
}
28+
29+
void performAction(char* (*actionFunc)(char*), const std::string& arg, const std::string& actionName) {
30+
const char* response = actionFunc((char*)arg.c_str());
31+
handleResponse(isStatusSuccess(response), actionName + " succeeded", actionName + " failed", response);
32+
}
33+
34+
void performAction(char* (*actionFunc)(), const std::string& actionName) {
35+
const char* response = actionFunc();
36+
handleResponse(isStatusSuccess(response), actionName + " succeeded", actionName + " failed", response);
37+
}
38+
39+
int main() {
40+
std::cout << "Starting IPFS from C++ Land ..." << std::endl;
41+
const char* startResponse = Start((char*)"./ipfs", 16969);
42+
43+
std::cout << "Add Peer" << std::endl;
44+
performAction(AddPeer, "/ip4/104.131.131.82/udp/4001/quic-v1/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ", "Add Peer");
45+
46+
sleep(5);
47+
48+
std::cout << "Remove Peer" << std::endl;
49+
performAction(RemovePeer, "/ip4/104.131.131.82/udp/4001/quic-v1/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ", "Remove Peer");
50+
51+
try {
52+
json parsedStart = json::parse(startResponse);
53+
std::string peerId = parsedStart["Data"]["peerId"];
54+
std::cout << "Started with Peer ID: " << peerId << std::endl;
55+
56+
const char* addResponse = Add((char*)"/home/hayzam/Projects/libipfs-new/bin/example.cpp");
57+
json parsedAdd = json::parse(addResponse);
58+
std::string cid = parsedAdd["Data"]["cid"];
59+
std::cout << "Added example.cpp file -> CID: " << cid << std::endl;
60+
61+
performAction(Pin, cid, "Pin CID");
62+
63+
std::cout << "Sleeping for a bit after pinning..." << std::endl;
64+
sleep(5);
65+
66+
performAction(Unpin, cid, "Unpin CID");
67+
performAction(GarbageCollect, "Garbage Collect");
68+
69+
const std::string targetPath = "./downloaded.txt";
70+
const std::string getCid = "/ipfs/bafybeifx7yeb55armcsxwwitkymga5xf53dxiarykms3ygqic223w5sk3m";
71+
if (!isStatusSuccess(Get((char*)getCid.c_str(), (char*)targetPath.c_str(), true))) {
72+
std::cerr << "Failed to get CID: " << getCid << std::endl;
73+
} else {
74+
std::cout << "Got CID: " << getCid << " and saved to " << targetPath << std::endl;
75+
}
76+
77+
sleep(60);
78+
79+
std::cout << Stop() << std::endl;
80+
} catch (const json::exception& e) {
81+
std::cerr << "JSON Parsing Error: " << e.what() << std::endl;
82+
return 1;
83+
}
84+
85+
return 0;
86+
}

example/Makefile

Lines changed: 0 additions & 20 deletions
This file was deleted.

example/example.cpp

Lines changed: 0 additions & 34 deletions
This file was deleted.

example/test-file.jpg

-463 KB
Binary file not shown.

0 commit comments

Comments
 (0)