github.com/nspcc-dev/neo-go@v0.105.2-0.20240517133400-6be757af3eba/pkg/rpcclient/local.go (about) 1 package rpcclient 2 3 import ( 4 "context" 5 6 "github.com/nspcc-dev/neo-go/pkg/neorpc" 7 ) 8 9 // InternalHook is a function signature that is required to create a local client 10 // (see NewInternal). It performs registration of local client's event channel 11 // and returns a request handler function. 12 type InternalHook func(context.Context, chan<- neorpc.Notification) func(*neorpc.Request) (*neorpc.Response, error) 13 14 // Internal is an experimental "local" client that does not connect to RPC via 15 // network. It's made for deeply integrated applications like NeoFS that have 16 // blockchain running in the same process, so use it only if you know what you're 17 // doing. It provides the same interface WSClient does. 18 type Internal struct { 19 WSClient 20 21 events chan neorpc.Notification 22 } 23 24 // NewInternal creates an instance of internal client. It accepts a method 25 // provided by RPC server. 26 func NewInternal(ctx context.Context, register InternalHook) (*Internal, error) { 27 c := &Internal{ 28 WSClient: WSClient{ 29 Client: Client{}, 30 31 shutdown: make(chan struct{}), 32 readerDone: make(chan struct{}), 33 writerDone: make(chan struct{}), 34 subscriptions: make(map[string]notificationReceiver), 35 receivers: make(map[any][]string), 36 }, 37 events: make(chan neorpc.Notification), 38 } 39 40 err := initClient(ctx, &c.WSClient.Client, "localhost:0", Options{}) 41 if err != nil { 42 return nil, err // Can't really happen for internal client. 43 } 44 c.cli = nil 45 go c.eventLoop() 46 // c.ctx is inherited from ctx in fact (see initClient). 47 c.requestF = register(c.ctx, c.events) //nolint:contextcheck // Non-inherited new context, use function like `context.WithXXX` instead 48 return c, nil 49 } 50 51 func (c *Internal) eventLoop() { 52 eventloop: 53 for { 54 select { 55 case <-c.ctx.Done(): 56 break eventloop 57 case <-c.shutdown: 58 break eventloop 59 case ev := <-c.events: 60 ntf := Notification{Type: ev.Event} 61 if len(ev.Payload) > 0 { 62 ntf.Value = ev.Payload[0] 63 } 64 c.notifySubscribers(ntf) 65 } 66 } 67 close(c.readerDone) 68 c.ctxCancel() 69 // ctx is cancelled, server is notified and will finish soon. 70 drainloop: 71 for { 72 select { 73 case <-c.events: 74 default: 75 break drainloop 76 } 77 } 78 close(c.events) 79 }