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  }