func TestSend(t *testing.T) { client, server := net.Pipe() go doServiceHandshake(server, true, t) cn, err := NewConnectionFromNetConn("TestRPCService", client) c := cn.(*Conn) s := rpc.NewServer() var ts TestRPCService s.Register(&ts) go s.ServeCodec(bsonrpc.NewServerCodec(server)) var tp TestParam tp.Val1 = "Hello World" tp.Val2 = 10 ri := &skynet.RequestInfo{} ts.TestMethod = func(in skynet.ServiceRPCIn, out *skynet.ServiceRPCOut) (err error) { out.Out, err = bson.Marshal(&tp) var t TestParam if err != nil { return } if in.ClientID != c.clientID { return errors.New("Failed to set ClientID on request") } if in.Method != "Foo" { return errors.New("Failed to set Method on request") } if *in.RequestInfo != *ri { return errors.New("Failed to set RequestInfo on request") } err = bson.Unmarshal(in.In, &t) if err != nil { return } if t.Val1 != tp.Val1 || tp.Val2 != tp.Val2 { return errors.New("Request failed to send proper data") } return } err = c.Send(ri, "Foo", tp, &tp) if err != nil { t.Error(err) return } c.Close() server.Close() }
// this function is the goroutine that owns this service - all thread-sensitive data needs to // be manipulated only through here. func (s *Service) mux() { loop: for { select { case conn := <-s.connectionChan: clientID := config.NewUUID() s.clientMutex.Lock() s.ClientInfo[clientID] = ClientInfo{ Address: conn.RemoteAddr(), } s.clientMutex.Unlock() // send the server handshake sh := skynet.ServiceHandshake{ Registered: s.Registered, ClientID: clientID, } encoder := bsonrpc.NewEncoder(conn) err := encoder.Encode(sh) if err != nil { log.Println(log.ERROR, "Failed to encode server handshake", err.Error()) continue } if !s.Registered { conn.Close() continue } // read the client handshake var ch skynet.ClientHandshake decoder := bsonrpc.NewDecoder(conn) err = decoder.Decode(&ch) if err != nil { log.Println(log.ERROR, "Error calling bsonrpc.NewDecoder: "+err.Error()) continue } // here do stuff with the client handshake go func() { s.RPCServ.ServeCodec(bsonrpc.NewServerCodec(conn)) }() case register := <-s.registeredChan: if register { s.register() } else { s.unregister() } case <-s.shutdownChan: s.shutdown() case _ = <-s.doneChan: break loop } } }