main.go (3466B)
1 package main 2 3 import ( 4 "context" 5 "errors" 6 "flag" 7 "fmt" 8 "log" 9 "log/slog" 10 "net" 11 "os" 12 "os/signal" 13 "runtime/pprof" 14 "syscall" 15 16 "capnproto.org/go/capnp/v3" 17 "capnproto.org/go/capnp/v3/flowcontrol" 18 "capnproto.org/go/capnp/v3/rpc" 19 "github.com/MTRNord/matrix_protobuf_fed/rpcserver" 20 21 protocol "github.com/MTRNord/matrix_protobuf_fed/proto/federation/v1" 22 ) 23 24 // This implements a dummy server for testing purposes of the rough api design especially around signatures 25 26 // Serve serves a Cap'n Proto RPC to incoming connections. 27 // 28 // Serve will take ownership of bootstrapClient and release it after the listener closes. 29 // 30 // Serve exits with the listener error if the listener is closed by the owner. 31 func Serve(lis net.Listener, boot capnp.Client) error { 32 if !boot.IsValid() { 33 err := errors.New("bootstrap client is not valid") 34 return err 35 } 36 // Since we took ownership of the bootstrap client, release it after we're done. 37 defer boot.Release() 38 for { 39 // Accept incoming connections 40 conn, err := lis.Accept() 41 if err != nil { 42 conn.Close() 43 return err 44 } 45 defer conn.Close() 46 47 // the RPC connection takes ownership of the bootstrap interface and will release it when the connection 48 // exits, so use AddRef to avoid releasing the provided bootstrap client capability. 49 opts := rpc.Options{ 50 BootstrapClient: boot.AddRef(), 51 Logger: slog.Default(), 52 } 53 // For each new incoming connection, create a new RPC transport connection that will serve incoming RPC requests 54 transport := rpc.NewStreamTransport(conn) 55 defer transport.Close() 56 rpc_conn := rpc.NewConn(transport, &opts) 57 defer rpc_conn.Close() 58 } 59 } 60 61 // ListenAndServe opens a listener on the given address and serves a Cap'n Proto RPC to incoming connections 62 // 63 // network and address are passed to net.Listen. Use network "unix" for Unix Domain Sockets 64 // and "tcp" for regular TCP IP4 or IP6 connections. 65 // 66 // ListenAndServe will take ownership of bootstrapClient and release it on exit. 67 func ListenAndServe(ctx context.Context, network, addr string, bootstrapClient capnp.Client) error { 68 listener, err := net.Listen(network, addr) 69 70 if err == nil { 71 // to close this listener, close the context 72 go func() { 73 <-ctx.Done() 74 _ = listener.Close() 75 }() 76 err = Serve(listener, bootstrapClient) 77 } 78 return err 79 } 80 81 var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file") 82 var memprofile = flag.String("memprofile", "", "write memory profile to this file") 83 var f *os.File 84 85 func main() { 86 flag.Parse() 87 if *cpuprofile != "" { 88 f, err := os.Create(*cpuprofile) 89 if err != nil { 90 log.Fatal(err) 91 } 92 pprof.StartCPUProfile(f) 93 defer pprof.StopCPUProfile() 94 } 95 96 c := make(chan os.Signal, 2) 97 signal.Notify(c, os.Interrupt, syscall.SIGTERM) // subscribe to system signals 98 onKill := func(c chan os.Signal) { 99 select { 100 case <-c: 101 fmt.Println("Got killed") 102 pprof.StopCPUProfile() 103 f.Close() 104 if *memprofile != "" { 105 f, err := os.Create(*memprofile) 106 if err != nil { 107 log.Fatal(err) 108 } 109 pprof.WriteHeapProfile(f) 110 f.Close() 111 } 112 os.Exit(0) 113 } 114 } 115 116 // try to handle os interrupt(signal terminated) 117 go onKill(c) 118 119 log.Println("Starting server on port localhost:8449") 120 server := rpcserver.NewServer() 121 122 client := protocol.MatrixFederation_ServerToClient(server) 123 client.SetFlowLimiter(flowcontrol.NewFixedLimiter(1 << 17)) 124 125 ListenAndServe(context.Background(), "tcp", "localhost:8449", capnp.Client(client)) 126 }