cln4go client
At the current state of the library the client provided by cln4go is really minimal and it do not provide a typed module with all the types of core lightning API, this feature is left for the future when a modular code generator will be ready.
For the moment the definition of the types are left to the user of this library, to give also the flexibility to define only the model that the user needs. However, with the go generics feature this library is still strongly typed, and allow to make typed calls to core lightning.
Basic Usage of the Client
The client is implemented with a procedural programming style due the limitation of go generics that do not allow to have generics paramters on a single method of a struct.
So, a basic usage of the client is
package main
import (
"fmt",
"os",
cln "github.com/vincenzopalazzo/cln4go/client"
)
var rpc *cln.UnixRPC
type Map = map[string]any
func init() {
path := os.Getenv("CLN_UNIX_SOCKET")
if path == "" {
err := fmt.Errorf("Unix path not exported with the CLN_UNIX_SOCKET env variable")
panic(err)
}
rpc, _ = cln.NewUnix(path)
}
func main() {
getinfo, err := cln.Call[Map, Map](rpc, "getinfo", map[string]any{})
if err != nil {
fmt.Printf("cln4go core lightning error: %s", err)
} else {
fmt.Printf("cln4go getinfo: node alias %s", getinfo["alias"])
}
}
Improve Client performance
One of the pain of golang is the reflection used to encode and decode an object from and to JSON, and this can be very downgrading while using the library in a restricted env like a raspberry pi 2/3.
In order to work around this problem, the client is able to change the encoder that it is used internally to encode and decode the json, and the definition of this encoder is left to the user of the library.
A example of custom encoder that use the library go-json that made the conversion from and to json without reflection is reported below
package json
import (
"fmt"
json "github.com/goccy/go-json"
)
type FastJSON struct{}
func (self *FastJSON) EncodeToByte(obj any) ([]byte, error) {
return json.Marshal(obj)
}
func (self *FastJSON) EncodeToString(obj any) (*string, error) {
jsonByte, err := json.Marshal(obj)
if err != nil {
return nil, err
}
jsonStr := string(jsonByte)
return &jsonStr, nil
}
func (self *FastJSON) DecodeFromString(jsonStr *string, obj any) error {
return json.Unmarshal([]byte(*jsonStr), &obj)
}
func (self *FastJSON) DecodeFromBytes(jsonByte []byte, obj any) error {
if len(jsonByte) == 0 {
return fmt.Errorf("encoding a null byte array")
}
return json.Unmarshal(jsonByte, &obj)
}
Now we use the encoder as
package main
import (
"fmt",
"os",
json "./json.go"
cln "github.com/vincenzopalazzo/cln4go/client"
)
var rpc *cln.UnixRPC
type Map = map[string]any
func init() {
path := os.Getenv("CLN_UNIX_SOCKET")
if path == "" {
err := fmt.Errorf("Unix path not exported with the CLN_UNIX_SOCKET env variable")
panic(err)
}
rpc, _ = cln.NewUnix(path)
rpc.SetEncoder(&json.FastJSON{})
}
func main() {
getinfo, err := cln.Call[Map, Map](rpc, "getinfo", map[string]any{})
if err != nil {
fmt.Printf("cln4go core lightning error: %s", err)
} else {
fmt.Printf("cln4go getinfo: node alias %s", getinfo["alias"])
}
}
A benchmark with the popular library glightning is available here