func fightN(f1, f2 Factory, n int) []MatchResult { aiA := &aiAdapter{factory: f1, games: make(map[string]gameState)} aiB := &aiAdapter{factory: f2, games: make(map[string]gameState)} a1, a2 := net.Pipe() b1, b2 := net.Pipe() ca1, ca2 := rpc.StreamTransport(a1), rpc.StreamTransport(a2) cb1, cb2 := rpc.StreamTransport(b1), rpc.StreamTransport(b2) // Server-side srvA := botapi.Ai_ServerToClient(aiA) srvB := botapi.Ai_ServerToClient(aiB) serverConnA := rpc.NewConn(ca1, rpc.MainInterface(srvA.Client)) serverConnB := rpc.NewConn(cb1, rpc.MainInterface(srvB.Client)) defer serverConnA.Wait() defer serverConnB.Wait() // Client-side ctx := context.Background() clientConnA := rpc.NewConn(ca2) clientConnB := rpc.NewConn(cb2) defer clientConnA.Close() defer clientConnB.Close() clientA := localAI{botapi.Ai{Client: clientConnA.Bootstrap(ctx)}} clientB := localAI{botapi.Ai{Client: clientConnB.Bootstrap(ctx)}} matchRes := make([]MatchResult, n) // Run the game for i := 0; i < n; i++ { b := engine.EmptyBoard(engine.DefaultConfig) b.InitBoard(engine.DefaultConfig) for !b.IsFinished() { turnCtx, _ := context.WithTimeout(ctx, 30*time.Second) resA, _ := clientA.takeTurn(turnCtx, strconv.Itoa(i), b, engine.P1Faction) resB, _ := clientB.takeTurn(turnCtx, strconv.Itoa(i), b, engine.P2Faction) b.Update(resA, resB) } matchRes[i] = MatchResult{ P1Score: b.BotCount(1), P2Score: b.BotCount(2), } } return matchRes }
func client(ctx context.Context, c net.Conn) error { // Create a connection that we can use to get the HashFactory. conn := rpc.NewConn(rpc.StreamTransport(c)) defer conn.Close() // Get the "bootstrap" interface. This is the capability set with // rpc.MainInterface on the remote side. hf := hashes.HashFactory{Client: conn.Bootstrap(ctx)} // Now we can call methods on hf, and they will be sent over c. s := hf.NewSha1(ctx, nil).Hash() // s refers to a remote Hash. Method calls are delivered in order. s.Write(ctx, func(p hashes.Hash_write_Params) error { err := p.SetData([]byte("Hello, ")) return err }) s.Write(ctx, func(p hashes.Hash_write_Params) error { err := p.SetData([]byte("World!")) return err }) result, err := s.Sum(ctx, nil).Struct() if err != nil { return err } sha1Val, err := result.Hash() if err != nil { return err } fmt.Printf("sha1: %x\n", sha1Val) return nil }
func server(c net.Conn) error { // Create a new locally implemented HashFactory. main := hashes.HashFactory_ServerToClient(hashFactory{}) // Listen for calls, using the HashFactory as the bootstrap interface. conn := rpc.NewConn(rpc.StreamTransport(c), rpc.MainInterface(main.Client)) // Wait for connection to abort. err := conn.Wait() return err }
func Example() { // Create an in-memory transport. In a real application, you would probably // use a net.TCPConn (for RPC) or an os.Pipe (for IPC). p1, p2 := net.Pipe() t1, t2 := rpc.StreamTransport(p1), rpc.StreamTransport(p2) // Server-side srv := testcapnp.Adder_ServerToClient(AdderServer{}) serverConn := rpc.NewConn(t1, rpc.MainInterface(srv.Client)) defer serverConn.Wait() // Client-side ctx := context.Background() clientConn := rpc.NewConn(t2) defer clientConn.Close() adderClient := testcapnp.Adder{Client: clientConn.Bootstrap(ctx)} // Every client call returns a promise. You can make multiple calls // concurrently. call1 := adderClient.Add(ctx, func(p testcapnp.Adder_add_Params) error { p.SetA(5) p.SetB(2) return nil }) call2 := adderClient.Add(ctx, func(p testcapnp.Adder_add_Params) error { p.SetA(10) p.SetB(20) return nil }) // Calling Struct() on a promise waits until it returns. result1, err := call1.Struct() if err != nil { fmt.Println("Add #1 failed:", err) return } result2, err := call2.Struct() if err != nil { fmt.Println("Add #2 failed:", err) return } fmt.Println("Results:", result1.Result(), result2.Result()) // Output: // Results: 7 30 }
// Dial connects to a server at the given TCP address. func Dial(addr string) (*Client, error) { c, err := net.Dial("tcp", addr) if err != nil { return nil, err } conn := rpc.NewConn(rpc.StreamTransport(c)) return &Client{ conn: conn, connector: botapi.AiConnector{Client: conn.Bootstrap(context.TODO())}, }, nil }
// handleConn runs in its own goroutine, started by listen. func (e *aiEndpoint) handleConn(c net.Conn) { aic := &aiConnector{e: e} rc := rpc.NewConn(rpc.StreamTransport(c), rpc.MainInterface(botapi.AiConnector_ServerToClient(aic).Client)) rc.Wait() aic.drop() }