MCPcopy Create free account
hub / github.com/diillson/chatcli / DownloadPlugin

Method DownloadPlugin

server/handler_remote.go:230–287  ·  view source on GitHub ↗

DownloadPlugin streams the plugin binary to the client.

(req *pb.DownloadPluginRequest, stream pb.ChatCLIService_DownloadPluginServer)

Source from the content-addressed store, hash-verified

228
229// DownloadPlugin streams the plugin binary to the client.
230func (h *Handler) DownloadPlugin(req *pb.DownloadPluginRequest, stream pb.ChatCLIService_DownloadPluginServer) error {
231 if h.pluginManager == nil {
232 return status.Errorf(codes.Unavailable, "%s", i18n.T("server.remote.plugin_unavailable"))
233 }
234 if req.PluginName == "" {
235 return status.Errorf(codes.InvalidArgument, "%s", i18n.T("server.remote.plugin_name_required"))
236 }
237
238 plugin, ok := h.pluginManager.GetPlugin(req.PluginName)
239 if !ok {
240 return status.Errorf(codes.NotFound, "%s", i18n.T("server.remote.plugin_not_found", req.PluginName))
241 }
242
243 pluginPath := plugin.Path()
244 info, err := os.Stat(pluginPath)
245 if err != nil {
246 return status.Errorf(codes.Internal, "%s", i18n.T("server.remote.plugin_stat_error", err))
247 }
248
249 f, err := os.Open(pluginPath) //#nosec G304 -- path supplied by user/agent through validated tool surface (boundary check upstream)
250 if err != nil {
251 return status.Errorf(codes.Internal, "%s", i18n.T("server.remote.plugin_open_error", err))
252 }
253 defer f.Close()
254
255 const chunkSize = 64 * 1024 // 64KB chunks
256 buf := make([]byte, chunkSize)
257 filename := info.Name()
258 totalSize := info.Size()
259 first := true
260
261 for {
262 n, readErr := f.Read(buf)
263 if n > 0 {
264 resp := &pb.DownloadPluginResponse{
265 Chunk: buf[:n],
266 Done: false,
267 }
268 if first {
269 resp.Filename = filename
270 resp.TotalSize = totalSize
271 first = false
272 }
273 if err := stream.Send(resp); err != nil {
274 return err
275 }
276 }
277 if readErr == io.EOF {
278 break
279 }
280 if readErr != nil {
281 return status.Errorf(codes.Internal, "%s", i18n.T("server.remote.plugin_read_error", readErr))
282 }
283 }
284
285 // Send final empty chunk with done=true
286 return stream.Send(&pb.DownloadPluginResponse{Done: true})
287}

Callers

nothing calls this directly

Calls 9

TFunction · 0.92
ErrorfMethod · 0.80
GetPluginMethod · 0.80
PathMethod · 0.65
CloseMethod · 0.65
NameMethod · 0.65
ReadMethod · 0.65
SendMethod · 0.65
SizeMethod · 0.45

Tested by

no test coverage detected