// ServiceRPC.Forward is the entry point for RPC calls. It wraps actual RPC calls // and provides a slot for the RequestInfo. The parameters to the actual RPC // calls are transmitted in a []byte, and are then marshalled/unmarshalled on // either end. func (srpc *ServiceRPC) Forward(in ServiceRPCIn, out *ServiceRPCOut) (err error) { m, ok := srpc.methods[in.Method] if !ok { err = errors.New(fmt.Sprintf("No such method %q", in.Method)) return } inValuePtr := reflect.New(m.Type().In(2)) err = bson.Unmarshal(in.In, inValuePtr.Interface()) if err != nil { return } // Allocate the out parameter of the RPC call. outType := m.Type().In(3) var outValue reflect.Value switch outType.Kind() { case reflect.Ptr: outValue = reflect.New(m.Type().In(3).Elem()) case reflect.Map: outValue = reflect.MakeMap(outType) default: panic("illegal out param type") } startTime := time.Now().UnixNano() params := []reflect.Value{ reflect.ValueOf(srpc.delegate), reflect.ValueOf(in.RequestInfo), inValuePtr.Elem(), outValue, } returns := m.Call(params) duration := time.Now().UnixNano() - startTime mc := MethodCall{ MethodName: in.Method, RequestInfo: in.RequestInfo, Duration: duration, } if srpc.log != nil { srpc.log.Item(mc) } out.Out, err = bson.Marshal(outValue.Interface()) if err != nil { return } erri := returns[0].Interface() out.Err, _ = erri.(error) return }
func (d *Decoder) Decode(pv interface{}) (err error) { var lbuf [4]byte n, err := d.r.Read(lbuf[:]) if n == 0 { err = io.EOF return } if n != 4 { err = errors.New(fmt.Sprintf("Corrupted BSON stream: could only read %d", n)) return } if err != nil { return } length := (int(lbuf[0]) << 0) | (int(lbuf[1]) << 8) | (int(lbuf[2]) << 16) | (int(lbuf[3]) << 24) buf := make([]byte, length) copy(buf[0:4], lbuf[:]) _, err = d.r.Read(buf[4:]) if err != nil { return } err = bson.Unmarshal(buf, pv) return }
func (c *ServiceClient) Send(requestInfo *skynet.RequestInfo, funcName string, in interface{}, outPointer interface{}) (err error) { // TODO: timeout logic s, err := c.getConnection(0) if err != nil { c.Log.Item(err) return } if requestInfo == nil { requestInfo = &skynet.RequestInfo{ RequestID: skynet.UUID(), } } sin := service.ServiceRPCIn{ RequestInfo: requestInfo, Method: funcName, } sin.In, err = bson.Marshal(in) if err != nil { return } sout := service.ServiceRPCOut{} // TODO: Check for connectivity issue so that we can try to get another resource out of the pool err = s.rpcClient.Call(s.service.Config.Name+".Forward", sin, &sout) if err != nil { c.Log.Item(err) } err = bson.Unmarshal(sout.Out, outPointer) if err != nil { return } c.connectionPool.Put(s) return }