github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/kbfs/libkbfs/kbfs_service.go (about) 1 package libkbfs 2 3 import ( 4 "errors" 5 "io" 6 "net" 7 "sync" 8 9 "github.com/keybase/client/go/libkb" 10 "github.com/keybase/client/go/logger" 11 kbgitkbfs "github.com/keybase/client/go/protocol/kbgitkbfs1" 12 keybase1 "github.com/keybase/client/go/protocol/keybase1" 13 "github.com/keybase/client/go/systemd" 14 "github.com/keybase/go-framed-msgpack-rpc/rpc" 15 ) 16 17 // KBFSErrorUnwrapper unwraps errors from the KBFS service. 18 type KBFSErrorUnwrapper struct { 19 } 20 21 var _ rpc.ErrorUnwrapper = KBFSErrorUnwrapper{} 22 23 // MakeArg implements rpc.ErrorUnwrapper. 24 func (eu KBFSErrorUnwrapper) MakeArg() interface{} { 25 return &keybase1.Status{} 26 } 27 28 // UnwrapError implements rpc.ErrorUnwrapper. 29 func (eu KBFSErrorUnwrapper) UnwrapError(arg interface{}) (appError error, 30 dispatchError error) { 31 s, ok := arg.(*keybase1.Status) 32 if !ok { 33 return nil, errors.New("Error converting arg to keybase1.Status object in DiskCacheErrorUnwrapper.UnwrapError") 34 } 35 36 if s == nil || s.Code == 0 { 37 return nil, nil 38 } 39 40 switch s.Code { 41 case StatusCodeDiskBlockCacheError: 42 appError = DiskBlockCacheError{Msg: s.Desc} 43 default: 44 ase := libkb.AppStatusError{ 45 Code: s.Code, 46 Name: s.Name, 47 Desc: s.Desc, 48 Fields: make(map[string]string), 49 } 50 for _, f := range s.Fields { 51 ase.Fields[f.Key] = f.Value 52 } 53 appError = ase 54 } 55 56 return appError, nil 57 } 58 59 type kbfsServiceConfig interface { 60 diskBlockCacheGetter 61 logMaker 62 syncedTlfGetterSetter 63 } 64 65 // KBFSService represents a running KBFS service. 66 type KBFSService struct { 67 config kbfsServiceConfig 68 log logger.Logger 69 kbCtx Context 70 stopOnce sync.Once 71 stopCh chan struct{} 72 } 73 74 // NewKBFSService creates a new KBFSService. 75 func NewKBFSService(kbCtx Context, config kbfsServiceConfig) ( 76 *KBFSService, error) { 77 log := config.MakeLogger("FSS") 78 // Check to see if we're receiving a socket from systemd. If not, create 79 // one and bind to it. 80 listener, err := systemd.GetListenerFromEnvironment() 81 if err != nil { 82 return nil, err 83 } 84 if listener != nil { 85 log.Debug("Found listener in the environment. Listening on fd 3.") 86 } else { 87 log.Debug("No listener found in the environment. Binding a new socket.") 88 listener, err = kbCtx.BindToKBFSSocket() 89 if err != nil { 90 return nil, err 91 } 92 } 93 k := &KBFSService{ 94 config: config, 95 log: log, 96 kbCtx: kbCtx, 97 } 98 k.Run(listener) 99 return k, nil 100 } 101 102 // Run starts listening on the passed-in listener. 103 func (k *KBFSService) Run(l net.Listener) { 104 go func() { _ = k.listenLoop(l) }() 105 } 106 107 // registerProtocols registers protocols for this KBFSService. 108 func (k *KBFSService) registerProtocols( 109 srv *rpc.Server, xp rpc.Transporter) error { 110 // TODO: fill in with actual protocols. 111 protocols := []rpc.Protocol{ 112 kbgitkbfs.DiskBlockCacheProtocol(NewDiskBlockCacheService(k.config)), 113 } 114 for _, proto := range protocols { 115 if err := srv.Register(proto); err != nil { 116 return err 117 } 118 } 119 return nil 120 } 121 122 // handle creates a server on an established connection. 123 func (k *KBFSService) handle(c net.Conn) { 124 xp := rpc.NewTransport(c, k.kbCtx.NewRPCLogFactory(), k.kbCtx.NewNetworkInstrumenter(keybase1.NetworkSource_LOCAL), 125 libkb.WrapError, rpc.DefaultMaxFrameLength) 126 127 server := rpc.NewServer(xp, libkb.WrapError) 128 129 err := k.registerProtocols(server, xp) 130 131 if err != nil { 132 k.log.Warning("RegisterProtocols error: %s", err) 133 return 134 } 135 136 // Run the server, then wait for it or this KBFSService to finish. 137 serverCh := server.Run() 138 go func() { 139 select { 140 case <-k.stopCh: 141 case <-serverCh: 142 } 143 // Close is idempotent, so always close when we're done. 144 c.Close() 145 }() 146 <-serverCh 147 148 // err is always non-nil. 149 err = server.Err() 150 if err != io.EOF { 151 k.log.Warning("Run error: %s", err) 152 } 153 154 k.log.Debug("handle() complete") 155 } 156 157 // listenLoop listens on a passed-in listener and calls `handle` for any 158 // connection that is established on the listener. 159 func (k *KBFSService) listenLoop(l net.Listener) error { 160 go func() { 161 <-k.stopCh 162 l.Close() 163 }() 164 defer l.Close() 165 for { 166 c, err := l.Accept() 167 if err != nil { 168 if libkb.IsSocketClosedError(err) { 169 err = nil 170 } 171 172 k.log.Debug("listenLoop() done, error: %+v", err) 173 return err 174 } 175 go k.handle(c) 176 } 177 } 178 179 // Shutdown shuts down this KBFSService. 180 func (k *KBFSService) Shutdown() { 181 k.stopOnce.Do(func() { 182 close(k.stopCh) 183 }) 184 }