Skip to content

Commit

Permalink
plugin: add custommsg hook
Browse files Browse the repository at this point in the history
The custommsg plugin hook is the receiving counterpart to the dev-sendcustommsg RPC method and allows plugins to handle messages that are not handled internally.
  • Loading branch information
sputn1ck committed Jun 7, 2021
1 parent 720c467 commit 752261d
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 6 deletions.
66 changes: 60 additions & 6 deletions glightning/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,54 @@ const (
_OpenChannel Hook = "openchannel"
_HtlcAccepted Hook = "htlc_accepted"
_RpcCommand Hook = "rpc_command"
_CustomMsg Hook = "custommsg"
)

var lightningMethodRegistry map[string]*jrpc2.Method

// The custommsg plugin hook is the receiving counterpart to the dev-sendcustommsg RPC method
//and allows plugins to handle messages that are not handled internally.
type CustomMsgReceivedEvent struct {
PeerId string `json:"peer_id"`
Payload string `json:"payload"`
hook func(*CustomMsgReceivedEvent) (*CustomMsgReceivedResponse, error)
}

type _CustomMsgReceivedResult string

const _CustomMsgReceivedContinue _CustomMsgReceivedResult = "continue"
const _CustomMsgReceivedFail _CustomMsgReceivedResult = "fail"

type CustomMsgReceivedResponse struct {
Result _CustomMsgReceivedResult `json:"result"`
}

func (pc *CustomMsgReceivedEvent) New() interface{} {
return &CustomMsgReceivedEvent{
hook: pc.hook,
}
}

func (pc *CustomMsgReceivedEvent) Name() string {
return string(_CustomMsg)
}

func (pc *CustomMsgReceivedEvent) Call() (jrpc2.Result, error) {
return pc.hook(pc)
}

func (pc *CustomMsgReceivedEvent) Continue() *CustomMsgReceivedResponse {
return &CustomMsgReceivedResponse{
Result: _CustomMsgReceivedContinue,
}
}

func (pc *CustomMsgReceivedEvent) Fail() *CustomMsgReceivedResponse {
return &CustomMsgReceivedResponse{
Result: _CustomMsgReceivedFail,
}
}

// This hook is called whenever a peer has connected and successfully completed
// the cryptographic handshake. The parameters have the following structure if
// there is a channel with the peer:
Expand Down Expand Up @@ -1139,12 +1183,13 @@ func (p *Plugin) Log(message string, level LogLevel) {
// Map for registering hooks. Not the *most* elegant but
// it'll do for now.
type Hooks struct {
PeerConnected func(*PeerConnectedEvent) (*PeerConnectedResponse, error)
DbWrite func(*DbWriteEvent) (*DbWriteResponse, error)
InvoicePayment func(*InvoicePaymentEvent) (*InvoicePaymentResponse, error)
OpenChannel func(*OpenChannelEvent) (*OpenChannelResponse, error)
HtlcAccepted func(*HtlcAcceptedEvent) (*HtlcAcceptedResponse, error)
RpcCommand func(*RpcCommandEvent) (*RpcCommandResponse, error)
PeerConnected func(*PeerConnectedEvent) (*PeerConnectedResponse, error)
DbWrite func(*DbWriteEvent) (*DbWriteResponse, error)
InvoicePayment func(*InvoicePaymentEvent) (*InvoicePaymentResponse, error)
OpenChannel func(*OpenChannelEvent) (*OpenChannelResponse, error)
HtlcAccepted func(*HtlcAcceptedEvent) (*HtlcAcceptedResponse, error)
RpcCommand func(*RpcCommandEvent) (*RpcCommandResponse, error)
CustomMsgReceived func(*CustomMsgReceivedEvent) (*CustomMsgReceivedResponse, error)
}

func (p *Plugin) RegisterHooks(hooks *Hooks) error {
Expand Down Expand Up @@ -1202,6 +1247,15 @@ func (p *Plugin) RegisterHooks(hooks *Hooks) error {
}
p.hooks = append(p.hooks, _RpcCommand)
}
if hooks.CustomMsgReceived != nil {
err := p.server.Register(&CustomMsgReceivedEvent{
hook: hooks.CustomMsgReceived,
})
if err != nil {
return err
}
p.hooks = append(p.hooks, _CustomMsg)
}
return nil
}

Expand Down
30 changes: 30 additions & 0 deletions glightning/plugin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,36 @@ func TestHook_InvoicePaymentFail(t *testing.T) {
runTest(t, plugin, msg+"\n\n", resp)
}

func TestHook_Message(t *testing.T) {
initFn := getInitFunc(t, func(t *testing.T, options map[string]glightning.Option, config *glightning.Config) {
t.Error("Should not have called init when calling get manifest")
})
plugin := glightning.NewPlugin(initFn)
plugin.RegisterHooks(&glightning.Hooks{
CustomMsgReceived: func(event *glightning.CustomMsgReceivedEvent) (*glightning.CustomMsgReceivedResponse, error) {
return event.Continue(), nil
},
})
msg := `{"jsonrpc":"2.0", "id":"aloha", "method":"custommsg"}`
resp := `{"jsonrpc":"2.0","result":{"result":"continue"},"id":"aloha"}`
runTest(t, plugin, msg+"\n\n", resp)
}

func TestHook_MessageFail(t *testing.T) {
initFn := getInitFunc(t, func(t *testing.T, options map[string]glightning.Option, config *glightning.Config) {
t.Error("Should not have called init when calling get manifest")
})
plugin := glightning.NewPlugin(initFn)
plugin.RegisterHooks(&glightning.Hooks{
CustomMsgReceived: func(event *glightning.CustomMsgReceivedEvent) (*glightning.CustomMsgReceivedResponse, error) {
return event.Fail(), nil
},
})
msg := `{"jsonrpc":"2.0", "id":"aloha", "method":"custommsg"}`
resp := `{"jsonrpc":"2.0","result":{"result":"fail"},"id":"aloha"}`
runTest(t, plugin, msg+"\n\n", resp)
}

func TestSubscription_SendPaySuccess(t *testing.T) {
var wg sync.WaitGroup
defer await(t, &wg)
Expand Down

0 comments on commit 752261d

Please sign in to comment.