github.com/Kong/go-pdk@v0.11.0/server/pbserver.go (about) 1 package server 2 3 import ( 4 "encoding/binary" 5 "fmt" 6 "io" 7 "log" 8 "net" 9 10 "github.com/Kong/go-pdk" 11 "github.com/Kong/go-pdk/server/kong_plugin_protocol" 12 "google.golang.org/protobuf/proto" 13 ) 14 15 func servePb(conn net.Conn, rh *rpcHandler) { 16 var err error 17 var d, rd []byte 18 for { 19 d, err = readPbFrame(conn) 20 if err != nil { 21 break 22 } 23 24 rd, err = codecPb(rh, conn, d) 25 if err != nil { 26 break 27 } 28 29 err = writePbFrame(conn, rd) 30 if err != nil { 31 break 32 } 33 } 34 35 conn.Close() 36 if err != nil { 37 log.Print(err) 38 } 39 } 40 41 func readPbFrame(conn net.Conn) (data []byte, err error) { 42 var len uint32 43 err = binary.Read(conn, binary.LittleEndian, &len) 44 if err != nil { 45 return 46 } 47 48 data = make([]byte, len) 49 50 _, err = io.ReadFull(conn, data) 51 if err != nil { 52 return nil, err 53 } 54 55 return 56 } 57 58 func writePbFrame(conn net.Conn, data []byte) (err error) { 59 var len uint32 = uint32(len(data)) 60 err = binary.Write(conn, binary.LittleEndian, len) 61 if err != nil { 62 return 63 } 64 65 _, err = conn.Write(data) 66 67 return 68 } 69 70 func codecPb(rh *rpcHandler, conn net.Conn, data []byte) (retData []byte, err error) { 71 var m kong_plugin_protocol.RpcCall 72 err = proto.Unmarshal(data, &m) 73 if err != nil { 74 return 75 } 76 77 rm, err := handlePbCmd(rh, conn, &m) 78 if err != nil { 79 return 80 } 81 82 if rm != nil { 83 retData, err = proto.Marshal(rm) 84 } 85 86 return 87 } 88 89 func pbInstanceStatus(status InstanceStatus) *kong_plugin_protocol.RpcReturn_InstanceStatus { 90 return &kong_plugin_protocol.RpcReturn_InstanceStatus{ 91 InstanceStatus: &kong_plugin_protocol.InstanceStatus{ 92 Name: status.Name, 93 InstanceId: int32(status.Id), 94 StartedAt: status.StartTime, 95 }, 96 } 97 } 98 99 func handlePbCmd(rh *rpcHandler, conn net.Conn, m *kong_plugin_protocol.RpcCall) (rm *kong_plugin_protocol.RpcReturn, err error) { 100 switch c := m.Call.(type) { 101 case *kong_plugin_protocol.RpcCall_CmdGetPluginNames: 102 // log.Printf("GetPluginNames: %v", c) 103 104 case *kong_plugin_protocol.RpcCall_CmdGetPluginInfo: 105 // log.Printf("GetPluginInfo: %v", c) 106 107 case *kong_plugin_protocol.RpcCall_CmdStartInstance: 108 config := PluginConfig{ 109 Name: c.CmdStartInstance.Name, 110 Config: c.CmdStartInstance.Config, 111 } 112 var status InstanceStatus 113 err = rh.StartInstance(config, &status) 114 if err != nil { 115 return 116 } 117 118 rm = &kong_plugin_protocol.RpcReturn{ 119 Sequence: m.Sequence, 120 Return: pbInstanceStatus(status), 121 } 122 123 case *kong_plugin_protocol.RpcCall_CmdGetInstanceStatus: 124 var status InstanceStatus 125 err = rh.InstanceStatus(int(c.CmdGetInstanceStatus.InstanceId), &status) 126 if err != nil { 127 return 128 } 129 130 rm = &kong_plugin_protocol.RpcReturn{ 131 Sequence: m.Sequence, 132 Return: pbInstanceStatus(status), 133 } 134 135 case *kong_plugin_protocol.RpcCall_CmdCloseInstance: 136 var status InstanceStatus 137 err = rh.CloseInstance(int(c.CmdCloseInstance.InstanceId), &status) 138 if err != nil { 139 return 140 } 141 rm = &kong_plugin_protocol.RpcReturn{ 142 Sequence: m.Sequence, 143 Return: pbInstanceStatus(status), 144 } 145 146 case *kong_plugin_protocol.RpcCall_CmdHandleEvent: 147 err = handlePbEvent(rh, conn, c.CmdHandleEvent) 148 rm = &kong_plugin_protocol.RpcReturn{ 149 Sequence: m.Sequence, 150 } 151 152 default: 153 err = fmt.Errorf("RPC call has unexpected type %T", c) 154 } 155 156 return 157 } 158 159 func handlePbEvent(rh *rpcHandler, conn net.Conn, e *kong_plugin_protocol.CmdHandleEvent) error { 160 rh.lock.RLock() 161 instance, ok := rh.instances[int(e.InstanceId)] 162 rh.lock.RUnlock() 163 if !ok { 164 return fmt.Errorf("no plugin instance %d", e.InstanceId) 165 } 166 167 h, ok := instance.handlers[e.EventName] 168 if !ok { 169 return fmt.Errorf("undefined method %s", e.EventName) 170 } 171 172 pdk := pdk.Init(conn) 173 174 h(pdk) 175 return writePbFrame(conn, []byte{}) 176 } 177 178 // Start the embedded plugin server, ProtoBuf version. 179 // Handles CLI flags, and returns immediately if appropriate. 180 // Otherwise, returns only if the server is stopped. 181 func StartServer(constructor func() interface{}, version string, priority int) error { 182 parseCli() 183 184 rh := newRpcHandler(constructor, version, priority) 185 186 if *dump { 187 dumpInfo(rh) 188 return nil 189 } 190 191 listener, err := openSocket() 192 if err != nil { 193 return err 194 } 195 defer listener.Close() 196 197 for { 198 conn, err := listener.Accept() 199 if err != nil { 200 log.Fatal(err) 201 } 202 203 go servePb(conn, rh) 204 } 205 }