commit 1f5750ca7cdd7184d68f101b715cb210be042dcc
parent bc5d5198a156fe7d94e4ba219ebd933a5595275c
Author: William Casarin <jb55@jb55.com>
Date: Sun, 30 Jan 2022 11:34:03 -0800
rpc working
Signed-off-by: William Casarin <jb55@jb55.com>
Diffstat:
11 files changed, 447 insertions(+), 6 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -0,0 +1 @@
+*xcuserdata*
diff --git a/.gitmodules b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "lnsocket"]
+ path = lnsocket
+ url = git://jb55.com/lnsocket
diff --git a/lightninglink-c/lightninglink-Bridging-Header.h b/lightninglink-c/lightninglink-Bridging-Header.h
@@ -0,0 +1,5 @@
+//
+// Use this file to import your target's public headers that you would like to expose to Swift.
+//
+
+#include "lightninglink.h"
diff --git a/lightninglink-c/lightninglink.c b/lightninglink-c/lightninglink.c
@@ -0,0 +1,18 @@
+//
+// lightninglink.c
+// lightninglink
+//
+// Created by William Casarin on 2022-01-07.
+//
+
+#include "lightninglink.h"
+#include <sys/select.h>
+
+
+void fd_do_set(int socket, fd_set *set) {
+ FD_SET(socket, set);
+}
+
+void fd_do_zero(fd_set *set) {
+ FD_ZERO(set);
+}
diff --git a/lightninglink-c/lightninglink.h b/lightninglink-c/lightninglink.h
@@ -0,0 +1,17 @@
+//
+// lightninglink.h
+// lightninglink
+//
+// Created by William Casarin on 2022-01-07.
+//
+
+#ifndef lightninglink_h
+#define lightninglink_h
+
+#include "lnsocket.h"
+#include "commando.h"
+
+void fd_do_zero(fd_set *);
+void fd_do_set(int, fd_set *);
+
+#endif /* lightninglink_h */
diff --git a/lightninglink.xcodeproj/project.pbxproj b/lightninglink.xcodeproj/project.pbxproj
@@ -14,6 +14,13 @@
4C641D2A2788FF30002A36C9 /* lightninglinkTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C641D292788FF30002A36C9 /* lightninglinkTests.swift */; };
4C641D342788FF31002A36C9 /* lightninglinkUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C641D332788FF31002A36C9 /* lightninglinkUITests.swift */; };
4C641D362788FF31002A36C9 /* lightninglinkUITestsLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C641D352788FF31002A36C9 /* lightninglinkUITestsLaunchTests.swift */; };
+ 4C641D492789083E002A36C9 /* lightninglink.c in Sources */ = {isa = PBXBuildFile; fileRef = 4C641D482789083E002A36C9 /* lightninglink.c */; };
+ 4C641D4B279CFA32002A36C9 /* lnsocket in Resources */ = {isa = PBXBuildFile; fileRef = 4C641D4A279CFA32002A36C9 /* lnsocket */; };
+ 4C873FCF27A62DC1008C972C /* lnsocket.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C873FCE27A62DC1008C972C /* lnsocket.a */; };
+ 4C873FD127A62DE7008C972C /* libsodium.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C873FD027A62DE7008C972C /* libsodium.a */; };
+ 4C873FD327A62DF5008C972C /* libsecp256k1.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C873FD227A62DF5008C972C /* libsecp256k1.a */; };
+ 4C873FD527A6EF3F008C972C /* LNSocket.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C873FD427A6EF3F008C972C /* LNSocket.swift */; };
+ 4C873FD727A6F1F5008C972C /* RPC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C873FD627A6F1F5008C972C /* RPC.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -44,6 +51,16 @@
4C641D2F2788FF31002A36C9 /* lightninglinkUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = lightninglinkUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
4C641D332788FF31002A36C9 /* lightninglinkUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = lightninglinkUITests.swift; sourceTree = "<group>"; };
4C641D352788FF31002A36C9 /* lightninglinkUITestsLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = lightninglinkUITestsLaunchTests.swift; sourceTree = "<group>"; };
+ 4C641D462789083E002A36C9 /* lightninglink-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "lightninglink-Bridging-Header.h"; sourceTree = "<group>"; };
+ 4C641D472789083E002A36C9 /* lightninglink.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = lightninglink.h; sourceTree = "<group>"; };
+ 4C641D482789083E002A36C9 /* lightninglink.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = lightninglink.c; sourceTree = "<group>"; };
+ 4C641D4A279CFA32002A36C9 /* lnsocket */ = {isa = PBXFileReference; lastKnownFileType = folder; path = lnsocket; sourceTree = "<group>"; };
+ 4C873FCC27A62DA8008C972C /* ios */ = {isa = PBXFileReference; lastKnownFileType = folder; name = ios; path = lnsocket/target/ios; sourceTree = "<group>"; };
+ 4C873FCE27A62DC1008C972C /* lnsocket.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = lnsocket.a; path = lnsocket/target/ios/lnsocket.a; sourceTree = "<group>"; };
+ 4C873FD027A62DE7008C972C /* libsodium.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libsodium.a; path = lnsocket/target/ios/libsodium.a; sourceTree = "<group>"; };
+ 4C873FD227A62DF5008C972C /* libsecp256k1.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libsecp256k1.a; path = lnsocket/target/ios/libsecp256k1.a; sourceTree = "<group>"; };
+ 4C873FD427A6EF3F008C972C /* LNSocket.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LNSocket.swift; sourceTree = "<group>"; };
+ 4C873FD627A6F1F5008C972C /* RPC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RPC.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -51,6 +68,9 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
+ 4C873FD327A62DF5008C972C /* libsecp256k1.a in Frameworks */,
+ 4C873FD127A62DE7008C972C /* libsodium.a in Frameworks */,
+ 4C873FCF27A62DC1008C972C /* lnsocket.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -74,10 +94,13 @@
4C641D0C2788FF2F002A36C9 = {
isa = PBXGroup;
children = (
+ 4C641D4A279CFA32002A36C9 /* lnsocket */,
+ 4C641D4227890715002A36C9 /* lightninglink-c */,
4C641D172788FF2F002A36C9 /* lightninglink */,
4C641D282788FF30002A36C9 /* lightninglinkTests */,
4C641D322788FF31002A36C9 /* lightninglinkUITests */,
4C641D162788FF2F002A36C9 /* Products */,
+ 4C873FCB27A62DA8008C972C /* Frameworks */,
);
sourceTree = "<group>";
};
@@ -94,10 +117,12 @@
4C641D172788FF2F002A36C9 /* lightninglink */ = {
isa = PBXGroup;
children = (
+ 4C873FD427A6EF3F008C972C /* LNSocket.swift */,
4C641D182788FF2F002A36C9 /* lightninglinkApp.swift */,
4C641D1A2788FF2F002A36C9 /* ContentView.swift */,
4C641D1C2788FF30002A36C9 /* Assets.xcassets */,
4C641D1E2788FF30002A36C9 /* Preview Content */,
+ 4C873FD627A6F1F5008C972C /* RPC.swift */,
);
path = lightninglink;
sourceTree = "<group>";
@@ -127,6 +152,27 @@
path = lightninglinkUITests;
sourceTree = "<group>";
};
+ 4C641D4227890715002A36C9 /* lightninglink-c */ = {
+ isa = PBXGroup;
+ children = (
+ 4C641D472789083E002A36C9 /* lightninglink.h */,
+ 4C641D482789083E002A36C9 /* lightninglink.c */,
+ 4C641D462789083E002A36C9 /* lightninglink-Bridging-Header.h */,
+ );
+ path = "lightninglink-c";
+ sourceTree = "<group>";
+ };
+ 4C873FCB27A62DA8008C972C /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ 4C873FD227A62DF5008C972C /* libsecp256k1.a */,
+ 4C873FD027A62DE7008C972C /* libsodium.a */,
+ 4C873FCE27A62DC1008C972C /* lnsocket.a */,
+ 4C873FCC27A62DA8008C972C /* ios */,
+ );
+ name = Frameworks;
+ sourceTree = "<group>";
+ };
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
@@ -195,6 +241,7 @@
TargetAttributes = {
4C641D142788FF2F002A36C9 = {
CreatedOnToolsVersion = 13.1;
+ LastSwiftMigration = 1310;
};
4C641D242788FF30002A36C9 = {
CreatedOnToolsVersion = 13.1;
@@ -233,6 +280,7 @@
files = (
4C641D202788FF30002A36C9 /* Preview Assets.xcassets in Resources */,
4C641D1D2788FF30002A36C9 /* Assets.xcassets in Resources */,
+ 4C641D4B279CFA32002A36C9 /* lnsocket in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -257,8 +305,11 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
+ 4C873FD527A6EF3F008C972C /* LNSocket.swift in Sources */,
4C641D1B2788FF2F002A36C9 /* ContentView.swift in Sources */,
+ 4C641D492789083E002A36C9 /* lightninglink.c in Sources */,
4C641D192788FF2F002A36C9 /* lightninglinkApp.swift in Sources */,
+ 4C873FD727A6F1F5008C972C /* RPC.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -346,7 +397,14 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = (
+ lnsocket,
+ lnsocket/deps/secp256k1/include,
+ lnsocket/deps/libsodium/src/libsodium/include,
+ );
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
+ "LD_RUNPATH_SEARCH_PATHS[arch=*]" = lnsocket/target/ios;
+ LIBRARY_SEARCH_PATHS = lnsocket/target/ios;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
@@ -401,7 +459,14 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = (
+ lnsocket,
+ lnsocket/deps/secp256k1/include,
+ lnsocket/deps/libsodium/src/libsodium/include,
+ );
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
+ "LD_RUNPATH_SEARCH_PATHS[arch=*]" = lnsocket/target/ios;
+ LIBRARY_SEARCH_PATHS = lnsocket/target/ios;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = iphoneos;
@@ -416,10 +481,11 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
+ CLANG_ENABLE_MODULES = YES;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_ASSET_PATHS = "\"lightninglink/Preview Content\"";
- DEVELOPMENT_TEAM = 5VWAH67C65;
+ DEVELOPMENT_TEAM = XK7H4JAB3D;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
@@ -431,10 +497,16 @@
"$(inherited)",
"@executable_path/Frameworks",
);
+ LIBRARY_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(PROJECT_DIR)/lnsocket/target/ios",
+ );
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.jb55.lightninglink;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = YES;
+ SWIFT_OBJC_BRIDGING_HEADER = "lightninglink-c/lightninglink-Bridging-Header.h";
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
@@ -445,10 +517,11 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
+ CLANG_ENABLE_MODULES = YES;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_ASSET_PATHS = "\"lightninglink/Preview Content\"";
- DEVELOPMENT_TEAM = 5VWAH67C65;
+ DEVELOPMENT_TEAM = XK7H4JAB3D;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
@@ -460,10 +533,15 @@
"$(inherited)",
"@executable_path/Frameworks",
);
+ LIBRARY_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(PROJECT_DIR)/lnsocket/target/ios",
+ );
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.jb55.lightninglink;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = YES;
+ SWIFT_OBJC_BRIDGING_HEADER = "lightninglink-c/lightninglink-Bridging-Header.h";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
diff --git a/lightninglink/ContentView.swift b/lightninglink/ContentView.swift
@@ -8,14 +8,26 @@
import SwiftUI
struct ContentView: View {
+ @State private var info: GetInfo
+
+ init(info: GetInfo) {
+ self.info = info
+ }
+
var body: some View {
- Text("Hello, world!")
- .padding()
+ let _self = self
+ VStack {
+ Text(self.info.alias)
+ Text("\(self.info.num_active_channels) active channels")
+ Text("\(self.info.msatoshi_fees_collected / 1000) sats collected in fees")
+ }
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
- ContentView()
+ Group {
+ ContentView(info: .empty)
+ }
}
}
diff --git a/lightninglink/LNSocket.swift b/lightninglink/LNSocket.swift
@@ -0,0 +1,90 @@
+
+import Foundation
+
+public class LNSocket {
+ var ln: OpaquePointer!
+
+ init() {
+ self.ln = lnsocket_create()
+ }
+
+ func genkey() {
+ lnsocket_genkey(self.ln)
+ }
+
+ func testrun() -> GetInfo? {
+ let node_id = "03f3c108ccd536b8526841f0a5c58212bb9e6584a1eb493080e7c1cc34f82dad71"
+ let host = "24.84.152.187"
+
+ self.genkey()
+
+ guard self.connect(node_id: node_id, host: host) else {
+ return nil
+ }
+
+ guard self.perform_init() else {
+ return nil
+ }
+
+ let res = rpc_getinfo(ln: self, token: "")
+
+ switch res {
+ case .success(let getinfo):
+ return getinfo
+
+ case .failure(let err):
+ print("\(err)")
+ return nil
+ }
+ }
+
+ func connect(node_id: String, host: String) -> Bool {
+ node_id.withCString { p_node_id in
+ host.withCString { p_host in
+ return lnsocket_connect(self.ln, p_node_id, p_host) != 0
+ }
+ }
+ }
+
+ func write(_ data: Data) -> Bool {
+ data.withUnsafeBytes { msg in
+ return lnsocket_write(self.ln, msg, UInt16(data.count)) != 0
+ }
+ }
+
+ func fd() -> Int32 {
+ var sock: Int32 = 0
+ lnsocket_fd(self.ln, &sock)
+ return sock
+ }
+
+ func recv() -> (UInt16, Data)? {
+ var msgtype: UInt16 = 0
+ var mpayload = UnsafeMutablePointer<UInt8>(nil)
+ var payload_len: UInt16 = 0
+
+ guard lnsocket_recv(self.ln, &msgtype, &mpayload, &payload_len) != 0 else {
+ return nil
+ }
+
+ guard let payload = mpayload else {
+ return nil
+ }
+
+ let data = Data(bytes: payload, count: Int(payload_len))
+
+ return (msgtype, data)
+ }
+
+ func perform_init() -> Bool {
+ return lnsocket_perform_init(self.ln) != 0
+ }
+
+ func print_errors() {
+ lnsocket_print_errors(self.ln)
+ }
+
+ deinit {
+ lnsocket_destroy(self.ln)
+ }
+}
diff --git a/lightninglink/RPC.swift b/lightninglink/RPC.swift
@@ -0,0 +1,209 @@
+//
+// RPC.swift
+// lightninglink
+//
+// Created by William Casarin on 2022-01-30.
+//
+
+import Foundation
+
+
+public typealias RequestRes<T> = Result<T, RequestError>
+
+public struct ResultWrapper<T: Decodable>: Decodable {
+ public var result: T
+}
+
+public struct GetInfo: Decodable {
+ public var alias: String
+ public var id: String
+ public var color: String
+ public var network: String
+ public var num_peers: Int
+ public var msatoshi_fees_collected: Int
+ public var num_active_channels: Int
+
+ public static var empty = GetInfo(alias: "", id: "", color: "", network: "", num_peers: 0, msatoshi_fees_collected: 0, num_active_channels: 0)
+}
+
+public enum RequestErrorType: Error {
+ case decoding(DecodingError)
+ case connectionFailed
+ case initFailed
+ case writeFailed
+ case timeout
+ case selectFailed
+ case recvFailed
+ case badCommandoMsgType(Int)
+ case badConnectionString
+ case outOfMemory
+ case encoding(EncodingError)
+ case status(Int)
+ case unknown(String)
+}
+
+public struct RequestError: Error, CustomStringConvertible {
+ public var response: HTTPURLResponse?
+ public var respData: Data = Data()
+ public var errorType: RequestErrorType
+
+ init(errorType: RequestErrorType) {
+ self.errorType = errorType
+ }
+
+ init(respData: Data, errorType: RequestErrorType) {
+ self.respData = respData
+ self.errorType = errorType
+ }
+
+ public var description: String {
+ let strData = String(decoding: respData, as: UTF8.self)
+
+ guard let resp = response else {
+ return "respData: \(strData)\nerrorType: \(errorType)\n"
+ }
+
+ return "response: \(resp)\nrespData: \(strData)\nerrorType: \(errorType)\n"
+ }
+}
+
+
+func parse_connection_string(_ cs: String) -> (String, String)? {
+ let arr = cs.components(separatedBy: "@")
+ if arr.count != 2 {
+ return nil
+ }
+ return (arr[0], arr[1])
+}
+
+public func performRpcOnce<IN: Encodable, OUT: Decodable>(
+ connectionString: String, operation: String, authToken: String,
+ params: IN
+) -> RequestRes<OUT> {
+ guard let parts = parse_connection_string(connectionString) else {
+ return .failure(RequestError(errorType: .badConnectionString))
+ }
+
+ let node_id = parts.0
+ let host = parts.1
+
+ let ln = LNSocket()
+ ln.genkey()
+
+ guard ln.connect(node_id: node_id, host: host) else {
+ return .failure(RequestError(errorType: .connectionFailed))
+ }
+
+ guard ln.perform_init() else {
+ return .failure(RequestError(errorType: .initFailed))
+ }
+
+ return performRpc(ln: ln, operation: operation, authToken: authToken, params: params)
+}
+
+public func performRpc<IN: Encodable, OUT: Decodable>(
+ ln: LNSocket, operation: String, authToken: String, params: IN) -> RequestRes<OUT>
+{
+
+ guard let msg = make_commando_msg(authToken: authToken, operation: operation, params: params) else {
+ return .failure(RequestError(errorType: .outOfMemory))
+ }
+
+ guard ln.write(msg) else {
+ return .failure(RequestError(errorType: .writeFailed))
+ }
+
+ switch commando_read_all(ln: ln) {
+ case .failure(let req_err):
+ return .failure(req_err)
+
+ case .success(let data):
+ return decodeJSON(data)
+ }
+}
+
+func decodeJSON<T: Decodable>(_ dat: Data) -> RequestRes<T> {
+ do {
+ let dat = try JSONDecoder().decode(ResultWrapper<T>.self, from: dat)
+ return .success(dat.result)
+ }
+ catch let decode_err as DecodingError {
+ return .failure(RequestError(respData: dat, errorType: .decoding(decode_err)))
+ }
+ catch let err {
+ return .failure(RequestError(respData: dat, errorType: .unknown("\(err)")))
+ }
+}
+
+
+func make_commando_msg<IN: Encodable>(authToken: String, operation: String, params: IN) -> Data? {
+ let encoder = JSONEncoder()
+ let json_data = try! encoder.encode(params)
+ guard let params_json = String(data: json_data, encoding: String.Encoding.utf8) else {
+ return nil
+ }
+ var buf = [UInt8](repeating: 0, count: 65536)
+ var outlen: UInt16 = 0
+ var ok: Bool = false
+
+ authToken.withCString { token in
+ operation.withCString { op in
+ params_json.withCString { ps in
+ ok = commando_make_rpc_msg(op, ps, token, 1, &buf, Int32(buf.capacity), &outlen) != 0
+ }}}
+
+ guard ok else {
+ return nil
+ }
+
+ return Data(buf[..<Int(outlen)])
+}
+
+
+func commando_read_all(ln: LNSocket, timeout_ms: Int32 = 2000) -> RequestRes<Data> {
+ var rv: Int32 = 0
+ var set = fd_set()
+ var timeout = timeval()
+
+ timeout.tv_sec = __darwin_time_t(timeout_ms / 1000);
+ timeout.tv_usec = (timeout_ms % 1000) * 1000;
+
+ fd_do_zero(&set)
+ let fd = ln.fd()
+ fd_do_set(fd, &set)
+
+ var all_data = Data()
+
+ while(true) {
+ rv = select(fd + 1, &set, nil, nil, &timeout)
+
+ if rv == -1 {
+ return .failure(RequestError(errorType: .selectFailed))
+ } else if rv == 0 {
+ return .failure(RequestError(errorType: .timeout))
+ }
+
+ guard let (msgtype, data) = ln.recv() else {
+ return .failure(RequestError(errorType: .recvFailed))
+ }
+
+ all_data.append(data[8...])
+
+ if msgtype == COMMANDO_REPLY_TERM {
+ break
+ } else if msgtype == COMMANDO_REPLY_CONTINUES {
+ continue
+ } else {
+ return .failure(RequestError(errorType: .badCommandoMsgType(Int(msgtype))))
+ }
+ }
+
+ return .success(all_data)
+}
+
+
+public func rpc_getinfo(ln: LNSocket, token: String) -> RequestRes<GetInfo>
+{
+ let params: Array<String> = []
+ return performRpc(ln: ln, operation: "getinfo", authToken: token, params: params)
+}
diff --git a/lightninglink/lightninglinkApp.swift b/lightninglink/lightninglinkApp.swift
@@ -9,9 +9,16 @@ import SwiftUI
@main
struct lightninglinkApp: App {
+ var info: GetInfo = .empty
+
+ init() {
+ let ln = LNSocket()
+ self.info = ln.testrun() ?? .empty
+ }
+
var body: some Scene {
WindowGroup {
- ContentView()
+ ContentView(info: self.info)
}
}
}
diff --git a/lnsocket b/lnsocket
@@ -0,0 +1 @@
+Subproject commit 3bc7497de143644c24ead95e516833c51e7c6ee8