-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
401 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
apply plugin: 'com.android.library' | ||
|
||
group = 'expo.modules.irohexpo' | ||
version = '0.6.0' | ||
|
||
def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle") | ||
apply from: expoModulesCorePlugin | ||
applyKotlinExpoModulesCorePlugin() | ||
useCoreDependencies() | ||
useExpoPublishing() | ||
|
||
// If you want to use the managed Android SDK versions from expo-modules-core, set this to true. | ||
// The Android SDK versions will be bumped from time to time in SDK releases and may introduce breaking changes in your module code. | ||
// Most of the time, you may like to manage the Android SDK versions yourself. | ||
def useManagedAndroidSdkVersions = false | ||
if (useManagedAndroidSdkVersions) { | ||
useDefaultAndroidSdkVersions() | ||
} else { | ||
buildscript { | ||
// Simple helper that allows the root project to override versions declared by this library. | ||
ext.safeExtGet = { prop, fallback -> | ||
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback | ||
} | ||
} | ||
project.android { | ||
compileSdkVersion safeExtGet("compileSdkVersion", 34) | ||
defaultConfig { | ||
minSdkVersion safeExtGet("minSdkVersion", 21) | ||
targetSdkVersion safeExtGet("targetSdkVersion", 34) | ||
} | ||
} | ||
} | ||
|
||
android { | ||
namespace "expo.modules.irohexpo" | ||
defaultConfig { | ||
versionCode 1 | ||
versionName "0.6.0" | ||
} | ||
lintOptions { | ||
abortOnError false | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
<manifest> | ||
</manifest> |
47 changes: 47 additions & 0 deletions
47
expo/iroh-expo/android/src/main/java/expo/modules/irohexpo/IrohExpoModule.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package expo.modules.irohexpo | ||
|
||
import expo.modules.kotlin.modules.Module | ||
import expo.modules.kotlin.modules.ModuleDefinition | ||
|
||
class IrohExpoModule : Module() { | ||
// Each module class must implement the definition function. The definition consists of components | ||
// that describes the module's functionality and behavior. | ||
// See https://docs.expo.dev/modules/module-api for more details about available components. | ||
override fun definition() = ModuleDefinition { | ||
// Sets the name of the module that JavaScript code will use to refer to the module. Takes a string as an argument. | ||
// Can be inferred from module's class name, but it's recommended to set it explicitly for clarity. | ||
// The module will be accessible from `requireNativeModule('IrohExpo')` in JavaScript. | ||
Name("IrohExpo") | ||
|
||
// Sets constant properties on the module. Can take a dictionary or a closure that returns a dictionary. | ||
Constants( | ||
"PI" to Math.PI | ||
) | ||
|
||
// Defines event names that the module can send to JavaScript. | ||
Events("onChange") | ||
|
||
// Defines a JavaScript synchronous function that runs the native code on the JavaScript thread. | ||
Function("hello") { | ||
"Hello world! 👋" | ||
} | ||
|
||
// Defines a JavaScript function that always returns a Promise and whose native code | ||
// is by default dispatched on the different thread than the JavaScript runtime runs on. | ||
AsyncFunction("setValueAsync") { value: String -> | ||
// Send an event to JavaScript. | ||
sendEvent("onChange", mapOf( | ||
"value" to value | ||
)) | ||
} | ||
|
||
// Enables the module to be used as a native view. Definition components that are accepted as part of | ||
// the view definition: Prop, Events. | ||
View(IrohExpoView::class) { | ||
// Defines a setter for the `name` prop. | ||
Prop("name") { view: IrohExpoView, prop: String -> | ||
println(prop) | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
{ | ||
"platforms": ["ios", "tvos", "android", "web"], | ||
"ios": { | ||
"modules": ["IrohExpoModule"] | ||
}, | ||
"android": { | ||
"modules": ["expo.modules.irohexpo.IrohExpoModule"] | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
// Import the native module. On web, it will be resolved to IrohExpo.web.ts | ||
// and on native platforms to IrohExpo.ts | ||
import IrohExpoModule from './src/IrohExpoModule'; | ||
import { AddrInfoOptions, ChangeEventPayload, ShareMode } from './src/IrohExpo.types'; | ||
|
||
export async function nodeId(): Promise<string> { | ||
return IrohExpoModule.nodeId(); | ||
} | ||
|
||
export async function docCreate(): Promise<Doc> { | ||
let id = await IrohExpoModule.docCreate(); | ||
return new Doc(id); | ||
} | ||
|
||
export async function docDrop(id: string) { | ||
return await IrohExpoModule.docDrop(id); | ||
} | ||
|
||
export async function docJoin(ticket: string): Promise<Doc> { | ||
let id = await IrohExpoModule.docJoin(ticket); | ||
return new Doc(id); | ||
} | ||
|
||
|
||
export class Doc { | ||
public id: string; | ||
|
||
constructor(id: string) { | ||
this.id = id; | ||
} | ||
|
||
async share(mode: ShareMode, addrOptions: AddrInfoOptions) { | ||
return IrohExpoModule.docShare(this.id, mode, addrOptions); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
import ExpoModulesCore | ||
import IrohLib | ||
|
||
/** | ||
* Options when creating a ticket | ||
*/ | ||
public enum AddrInfoOptionsString: String, Enumerable { | ||
/** | ||
* Only the Node ID is added. | ||
* | ||
* This usually means that iroh-dns discovery is used to find address information. | ||
*/ | ||
case id | ||
/** | ||
* Include both the relay URL and the direct addresses. | ||
*/ | ||
case relayAndAddresses | ||
/** | ||
* Only include the relay URL. | ||
*/ | ||
case relay | ||
/** | ||
* Only include the direct addresses. | ||
*/ | ||
case addresses | ||
} | ||
|
||
// convert to AddrInfoOptions | ||
extension AddrInfoOptionsString { | ||
func toAddrInfoOptions() -> AddrInfoOptions { | ||
switch self { | ||
case .id: | ||
return AddrInfoOptions.id | ||
case .addresses: | ||
return AddrInfoOptions.addresses | ||
case .relay: | ||
return AddrInfoOptions.relay | ||
case .relayAndAddresses: | ||
return AddrInfoOptions.relayAndAddresses | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Intended capability for document share tickets | ||
*/ | ||
public enum ShareModeString: String, Enumerable { | ||
/** | ||
* Read-only access | ||
*/ | ||
case read | ||
/** | ||
* Write access | ||
*/ | ||
case write | ||
} | ||
|
||
// convert to ShareMode | ||
extension ShareModeString { | ||
func toShareMode() -> ShareMode { | ||
switch self { | ||
case .read: | ||
return ShareMode.read | ||
case .write: | ||
return ShareMode.write | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
Pod::Spec.new do |s| | ||
s.name = 'IrohExpo' | ||
s.version = '1.0.0' | ||
s.summary = 'A sample project summary' | ||
s.description = 'A sample project description' | ||
s.author = '' | ||
s.homepage = 'https://docs.expo.dev/modules/' | ||
s.platforms = { :ios => '15.4', :tvos => '15.4' } | ||
s.source = { git: '' } | ||
s.static_framework = true | ||
|
||
s.dependency 'ExpoModulesCore' | ||
s.dependency 'IrohLib' | ||
|
||
# Swift/Objective-C compatibility | ||
s.pod_target_xcconfig = { | ||
'DEFINES_MODULE' => 'YES', | ||
'SWIFT_COMPILATION_MODE' => 'wholemodule' | ||
} | ||
|
||
s.source_files = "**/*.{h,m,mm,swift,hpp,cpp}" | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
import ExpoModulesCore | ||
import IrohLib | ||
|
||
public class IrohExpoModule: Module { | ||
private var node: IrohNode? | ||
|
||
private func irohPath() -> URL { | ||
let paths = FileManager.default.urls(for: .libraryDirectory, in: .userDomainMask) | ||
let irohPath = paths[0].appendingPathComponent("iroh") | ||
mkdirP(path: irohPath.path) | ||
return irohPath | ||
} | ||
|
||
public func definition() -> ModuleDefinition { | ||
Name("IrohExpo") | ||
|
||
OnCreate { | ||
do { | ||
// IrohLib.setLogLevel(level: .debug) | ||
// try IrohLib.startMetricsCollection() | ||
let path = self.irohPath() | ||
self.node = try IrohNode(path: path.path) | ||
} catch { | ||
print("error creating iroh node \(error)") | ||
} | ||
} | ||
|
||
AsyncFunction("nodeId") { | ||
return self.node?.nodeId() | ||
} | ||
|
||
AsyncFunction("docCreate") { | ||
guard let doc = try self.node?.docCreate() else { | ||
throw IrohError.Doc(description: "error creating doc") | ||
} | ||
return doc.id(); | ||
} | ||
|
||
AsyncFunction("docDrop") { (docId: String) in | ||
return try self.node?.docDrop(id: docId) | ||
} | ||
|
||
AsyncFunction("docOpen") { (docId: String) in | ||
return try self.node?.docOpen(id: docId) | ||
} | ||
|
||
AsyncFunction("docJoin") { (ticket: String) in | ||
return try self.node?.docJoin(ticket: ticket) | ||
} | ||
|
||
AsyncFunction("docShare") { (docId: String, mode: ShareModeString, addrOptions: AddrInfoOptionsString) in | ||
guard let doc = try self.node?.docOpen(id: docId) else { | ||
throw IrohError.Doc(description: "error opening doc") | ||
} | ||
return try doc.share(mode: mode.toShareMode(), addrOptions: addrOptions.toAddrInfoOptions()) | ||
} | ||
|
||
AsyncFunction("docSetBytes") { (docId: string, author: AuthorId, key: Data, bytes: Data) in | ||
guard let doc = try self.node?.docOpen(id: docId) else { | ||
throw IrohError.Doc(description: "error opening doc") | ||
} | ||
|
||
return try doc.setBytes(author: author, key: key, bytes: bytes) | ||
} | ||
} | ||
} | ||
|
||
func mkdirP(path: String) { | ||
let fileManager = FileManager.default | ||
do { | ||
try fileManager.createDirectory(atPath: path, | ||
withIntermediateDirectories: true, | ||
attributes: nil) | ||
} catch { | ||
print("Error creating directory: \(error)") | ||
} | ||
} | ||
|
||
|
||
|
||
/// A representation of a mutable, synchronizable key-value store. | ||
interface Doc { | ||
/// Get the document id of this doc. | ||
string id(); | ||
/// Close the document. | ||
void close(); | ||
/// Set the content of a key to a byte array. | ||
Hash set_bytes([ByRef] AuthorId author, bytes key, bytes value); | ||
/// Set an entries on the doc via its key, hash, and size. | ||
void set_hash(AuthorId author, bytes key, Hash hash, u64 size); | ||
/// Add an entry from an absolute file path | ||
void import_file(AuthorId author, bytes key, string path, boolean in_place, DocImportFileCallback? cb); | ||
/// Export an entry as a file to a given absolute path | ||
void export_file(Entry entry, string path, DocExportFileCallback? cb); | ||
/// Delete entries that match the given `author` and key `prefix`. | ||
/// | ||
/// This inserts an empty entry with the key set to `prefix`, effectively clearing all other | ||
/// entries whose key starts with or is equal to the given `prefix`. | ||
/// | ||
/// Returns the number of entries deleted. | ||
u64 del(AuthorId author_id, bytes prefix); | ||
/// Get the latest entry for a key and author. | ||
Entry? get_one(Query query); | ||
/// Get entries. | ||
/// | ||
/// Note: this allocates for each `Entry`, if you have many `Entry`s this may be a prohibitively large list. | ||
/// Please file an [issue](https://github.com/n0-computer/iroh-ffi/issues/new) if you run into this issue | ||
sequence<Entry> get_many(Query query); | ||
/// Get an entry for a key and author. | ||
/// | ||
/// Optionally also get the entry if it is empty (i.e. a deletion marker) | ||
Entry? get_exact(AuthorId author, bytes key, boolean include_empty); | ||
|
||
/// Share this document with peers over a ticket. | ||
string share(ShareMode mode, AddrInfoOptions addr_options); | ||
/// Start to sync this document with a list of peers. | ||
void start_sync(sequence<NodeAddr> peers); | ||
/// Stop the live sync for this document. | ||
void leave(); | ||
/// Subscribe to events for this document. | ||
void subscribe(SubscribeCallback cb); | ||
/// Get status info for this document | ||
OpenState status(); | ||
/// Set the download policy for this document | ||
void set_download_policy(DownloadPolicy policy); | ||
/// Get the download policy for this document | ||
DownloadPolicy get_download_policy(); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
export type ChangeEventPayload = { | ||
value: string; | ||
}; | ||
|
||
/// Options passed to [`IrohNode.new`]. Controls the behaviour of an iroh node. | ||
export type NodeOptions = { | ||
/// How frequently the blob store should clean up unreferenced blobs, in milliseconds. | ||
/// Set to 0 to disable gc | ||
GCIntervalMillis: number | ||
}; | ||
|
||
|
||
/// Intended capability for document share tickets | ||
export enum ShareMode { | ||
/// Read-only access | ||
read = "read", | ||
/// Write access | ||
write = "write", | ||
}; | ||
|
||
|
||
/// Options when creating a ticket | ||
export enum AddrInfoOptions { | ||
/// Only the Node ID is added. | ||
/// | ||
/// This usually means that iroh-dns discovery is used to find address information. | ||
id = "id", | ||
/// Include both the relay URL and the direct addresses. | ||
relayAndAddresses = "relayAndAddresses", | ||
/// Only include the relay URL. | ||
relay = "relay", | ||
/// Only include the direct addresses. | ||
addresses = "addresses", | ||
}; |
Oops, something went wrong.