github.com/gagliardetto/solana-go@v1.11.0/rpc/ws/programSubscribe.go (about) 1 // Copyright 2021 github.com/gagliardetto 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package ws 16 17 import ( 18 "github.com/gagliardetto/solana-go" 19 "github.com/gagliardetto/solana-go/rpc" 20 ) 21 22 type ProgramResult struct { 23 Context struct { 24 Slot uint64 25 } `json:"context"` 26 Value rpc.KeyedAccount `json:"value"` 27 } 28 29 // ProgramSubscribe subscribes to a program to receive notifications 30 // when the lamports or data for a given account owned by the program changes. 31 func (cl *Client) ProgramSubscribe( 32 programID solana.PublicKey, 33 commitment rpc.CommitmentType, 34 ) (*ProgramSubscription, error) { 35 return cl.ProgramSubscribeWithOpts( 36 programID, 37 commitment, 38 "", 39 nil, 40 ) 41 } 42 43 // ProgramSubscribe subscribes to a program to receive notifications 44 // when the lamports or data for a given account owned by the program changes. 45 func (cl *Client) ProgramSubscribeWithOpts( 46 programID solana.PublicKey, 47 commitment rpc.CommitmentType, 48 encoding solana.EncodingType, 49 filters []rpc.RPCFilter, 50 ) (*ProgramSubscription, error) { 51 52 params := []interface{}{programID.String()} 53 conf := map[string]interface{}{ 54 "encoding": "base64", 55 } 56 if commitment != "" { 57 conf["commitment"] = commitment 58 } 59 if encoding != "" { 60 conf["encoding"] = encoding 61 } 62 if filters != nil && len(filters) > 0 { 63 conf["filters"] = filters 64 } 65 66 genSub, err := cl.subscribe( 67 params, 68 conf, 69 "programSubscribe", 70 "programUnsubscribe", 71 func(msg []byte) (interface{}, error) { 72 var res ProgramResult 73 err := decodeResponseFromMessage(msg, &res) 74 return &res, err 75 }, 76 ) 77 if err != nil { 78 return nil, err 79 } 80 return &ProgramSubscription{ 81 sub: genSub, 82 }, nil 83 } 84 85 type ProgramSubscription struct { 86 sub *Subscription 87 } 88 89 func (sw *ProgramSubscription) Recv() (*ProgramResult, error) { 90 select { 91 case d := <-sw.sub.stream: 92 return d.(*ProgramResult), nil 93 case err := <-sw.sub.err: 94 return nil, err 95 } 96 } 97 98 func (sw *ProgramSubscription) Err() <-chan error { 99 return sw.sub.err 100 } 101 102 func (sw *ProgramSubscription) Response() <-chan *ProgramResult { 103 typedChan := make(chan *ProgramResult, 1) 104 go func(ch chan *ProgramResult) { 105 // TODO: will this subscription yield more than one result? 106 d, ok := <-sw.sub.stream 107 if !ok { 108 return 109 } 110 ch <- d.(*ProgramResult) 111 }(typedChan) 112 return typedChan 113 } 114 115 func (sw *ProgramSubscription) Unsubscribe() { 116 sw.sub.Unsubscribe() 117 }