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() }
func (sa *ServiceAdmin) Listen(addr *skynet.BindAddr, bindWait *sync.WaitGroup) { listener, err := addr.Listen() if err != nil { panic(err) } bindWait.Done() sa.service.Log.Trace(fmt.Sprintf("%+v", AdminListening{sa.service.Config})) for { conn, err := listener.AcceptTCP() if err != nil { panic(err) } go sa.rpc.ServeCodec(bsonrpc.NewServerCodec(conn)) } }
// 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: go func() { 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, Name: s.Name, } codec := bsonrpc.NewServerCodec(conn) log.Println(log.TRACE, "Sending ServiceHandshake") err := codec.Encoder.Encode(sh) if err != nil { log.Println(log.ERROR, "Failed to encode server handshake", err.Error()) conn.Close() return } if !s.Registered { log.Println(log.ERROR, "Connection attempted while unregistered. Closing connection") conn.Close() return } // read the client handshake var ch skynet.ClientHandshake log.Println(log.TRACE, "Reading ClientHandshake") err = codec.Decoder.Decode(&ch) if err != nil { log.Println(log.ERROR, "Error decoding ClientHandshake: "+err.Error()) conn.Close() return } // here do stuff with the client handshake log.Println(log.TRACE, "Handing connection to RPC layer") s.RPCServ.ServeCodec(codec) }() case register := <-s.registeredChan: if register { s.register() } else { s.unregister() } case <-s.shutdownChan: s.shutdown() case _ = <-s.doneChan: break loop } } }
// 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: atomic.AddInt32(&s.Stats.Clients, 1) clientID := skynet.UUID() 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 { s.Log.Error(err.Error()) atomic.AddInt32(&s.Stats.Clients, -1) break } if !s.Registered { conn.Close() atomic.AddInt32(&s.Stats.Clients, -1) break } // read the client handshake var ch skynet.ClientHandshake decoder := bsonrpc.NewDecoder(conn) err = decoder.Decode(&ch) if err != nil { s.Log.Error("Error calling bsonrpc.NewDecoder: " + err.Error()) atomic.AddInt32(&s.Stats.Clients, -1) break } // here do stuff with the client handshake go func() { s.RPCServ.ServeCodec(bsonrpc.NewServerCodec(conn)) atomic.AddInt32(&s.Stats.Clients, -1) }() case register := <-s.registeredChan: if register { s.register() } else { s.unregister() } case _ = <-s.doneChan: go func() { for _ = range s.doneChan { } }() s.RemoveFromCluster() s.doozerChan <- doozerFinish{} break loop case _ = <-s.updateTicker.C: s.UpdateDoozerStats() } } }