@@ -7,14 +7,13 @@ import (
77 "errors"
88 "log"
99 "math"
10- "net"
1110 "net/http"
1211 "net/url"
12+ "plugin"
1313 "strings"
1414 "sync"
1515
1616 "google.golang.org/grpc"
17- "google.golang.org/grpc/credentials"
1817 "google.golang.org/protobuf/types/known/emptypb"
1918 "gopkg.in/yaml.v2"
2019
@@ -32,19 +31,54 @@ type CompatV1 struct {
3231 GetInstance func (user * papiv1.UserContext ) (papiv1.Plugin , error )
3332}
3433
35- type PluginShim struct {
34+ // NewCompatV1FromPlugin creates a new CompatV1 from a native Go plugin.
35+ func NewCompatV1FromPlugin (plugin * plugin.Plugin ) (* CompatV1 , error ) {
36+ getPluginInfo , err := plugin .Lookup ("GetGotifyPluginInfo" )
37+ if err != nil {
38+ return nil , err
39+ }
40+ getInstance , err := plugin .Lookup ("NewGotifyPlugin" )
41+ if err != nil {
42+ return nil , err
43+ }
44+
45+ getPluginInfoChecked , ok := getPluginInfo .(func () * papiv1.Info )
46+ if ! ok {
47+ return nil , errors .New ("GetGotifyPluginInfo is not a function" )
48+ }
49+ getInstanceCheckedWithErr , ok := getInstance .(func (user * papiv1.UserContext ) (papiv1.Plugin , error ))
50+ if ! ok {
51+ if getInstanceCheckedWithoutErr , ok := getInstance .(func (user * papiv1.UserContext ) papiv1.Plugin ); ok {
52+ getInstanceCheckedWithErr = func (user * papiv1.UserContext ) (papiv1.Plugin , error ) {
53+ return getInstanceCheckedWithoutErr (user ), nil
54+ }
55+ } else {
56+ return nil , errors .New ("NewGotifyPlugin is not a function" )
57+ }
58+ }
59+
60+ return & CompatV1 {
61+ GetPluginInfo : getPluginInfoChecked ,
62+ GetInstance : getInstanceCheckedWithErr ,
63+ }, nil
64+ }
65+
66+ // CompatV1Shim is a shim that acts like a plugin server and delegates request to
67+ // something that implements a V1-style API interface.
68+ type CompatV1Shim struct {
3669 mu * sync.RWMutex
3770 compatV1 * CompatV1
3871 gin * gin.Engine
3972 instances map [uint64 ]papiv1.Plugin
4073 pluginServer * grpc.Server
4174 pluginInfo * papiv1.Info
75+ http.Server
4276 protobuf.UnimplementedPluginServer
4377 protobuf.UnimplementedDisplayerServer
4478 protobuf.UnimplementedConfigurerServer
4579}
4680
47- func (s * PluginShim ) GetPluginInfo (ctx context.Context , req * emptypb.Empty ) (* protobuf.Info , error ) {
81+ func (s * CompatV1Shim ) GetPluginInfo (ctx context.Context , req * emptypb.Empty ) (* protobuf.Info , error ) {
4882 return & protobuf.Info {
4983 Version : s .pluginInfo .Version ,
5084 Author : s .pluginInfo .Author ,
@@ -88,7 +122,7 @@ func (h *shimV1StorageHandler) Load() (b []byte, err error) {
88122 return
89123}
90124
91- func (s * PluginShim ) SetEnable (ctx context.Context , req * protobuf.SetEnableRequest ) (* emptypb.Empty , error ) {
125+ func (s * CompatV1Shim ) SetEnable (ctx context.Context , req * protobuf.SetEnableRequest ) (* emptypb.Empty , error ) {
92126 if req .User .Id > math .MaxUint {
93127 return nil , errors .New ("user id is too large" )
94128 }
@@ -105,7 +139,7 @@ func (s *PluginShim) SetEnable(ctx context.Context, req *protobuf.SetEnableReque
105139 }
106140}
107141
108- func (s * PluginShim ) Display (ctx context.Context , req * protobuf.DisplayRequest ) (* protobuf.DisplayResponse , error ) {
142+ func (s * CompatV1Shim ) Display (ctx context.Context , req * protobuf.DisplayRequest ) (* protobuf.DisplayResponse , error ) {
109143 if req .User .Id > math .MaxUint {
110144 return nil , errors .New ("user id is too large" )
111145 }
@@ -127,7 +161,7 @@ func (s *PluginShim) Display(ctx context.Context, req *protobuf.DisplayRequest)
127161 return nil , errors .New ("instance does not implement displayer" )
128162}
129163
130- func (s * PluginShim ) DefaultConfig (ctx context.Context , req * protobuf.DefaultConfigRequest ) (* protobuf.Config , error ) {
164+ func (s * CompatV1Shim ) DefaultConfig (ctx context.Context , req * protobuf.DefaultConfigRequest ) (* protobuf.Config , error ) {
131165 if req .User .Id > math .MaxUint {
132166 return nil , errors .New ("user id is too large" )
133167 }
@@ -150,7 +184,7 @@ func (s *PluginShim) DefaultConfig(ctx context.Context, req *protobuf.DefaultCon
150184 return nil , errors .New ("instance does not implement configurer" )
151185}
152186
153- func (s * PluginShim ) ValidateAndSetConfig (ctx context.Context , req * protobuf.ValidateAndSetConfigRequest ) (* protobuf.ValidateAndSetConfigResponse , error ) {
187+ func (s * CompatV1Shim ) ValidateAndSetConfig (ctx context.Context , req * protobuf.ValidateAndSetConfigRequest ) (* protobuf.ValidateAndSetConfigResponse , error ) {
154188 if req .User .Id > math .MaxUint {
155189 return nil , errors .New ("user id is too large" )
156190 }
@@ -183,7 +217,7 @@ func (s *PluginShim) ValidateAndSetConfig(ctx context.Context, req *protobuf.Val
183217 return nil , errors .New ("instance does not implement configurer" )
184218}
185219
186- func (s * PluginShim ) RunUserInstance (req * protobuf.UserInstanceRequest , stream protobuf.Plugin_RunUserInstanceServer ) error {
220+ func (s * CompatV1Shim ) RunUserInstance (req * protobuf.UserInstanceRequest , stream protobuf.Plugin_RunUserInstanceServer ) error {
187221 if req .User .Id > math .MaxUint {
188222 return errors .New ("user id is too large" )
189223 }
@@ -262,7 +296,7 @@ func (s *PluginShim) RunUserInstance(req *protobuf.UserInstanceRequest, stream p
262296 return nil
263297}
264298
265- func NewPluginRpc (compatV1 * CompatV1 , cliArgs []string ) (* PluginShim , error ) {
299+ func NewPluginRpc (compatV1 * CompatV1 , cliArgs []string ) (* CompatV1Shim , error ) {
266300 pluginInfo := compatV1 .GetPluginInfo ()
267301 tlsName := BuildPluginTLSName (purposePluginRPC , pluginInfo .Name )
268302
@@ -296,19 +330,14 @@ func NewPluginRpc(compatV1 *CompatV1, cliArgs []string) (*PluginShim, error) {
296330 RootCAs : rootCAs ,
297331 ServerName : tlsName ,
298332 ClientAuth : tls .RequireAndVerifyClientCert ,
299- VerifyConnection : func (state tls.ConnectionState ) error {
300- if state .ServerName != ServerTLSName {
301- return errors .New ("not implemented: client must be the gotify server itself for now" )
302- }
303- return nil
304- },
333+ ClientCAs : rootCAs ,
305334 }
306335
307- rpcServer := grpc .NewServer (grpc . Creds ( credentials . NewTLS ( tlsConfig )) )
336+ rpcServer := grpc .NewServer ()
308337
309338 gin := gin .Default ()
310339
311- self := & PluginShim {
340+ self := & CompatV1Shim {
312341 mu : & sync.RWMutex {},
313342 instances : make (map [uint64 ]papiv1.Plugin ),
314343 compatV1 : compatV1 ,
@@ -321,10 +350,19 @@ func NewPluginRpc(compatV1 *CompatV1, cliArgs []string) (*PluginShim, error) {
321350 protobuf .RegisterDisplayerServer (rpcServer , self )
322351 protobuf .RegisterConfigurerServer (rpcServer , self )
323352
353+ protocols := new (http.Protocols )
354+ protocols .SetHTTP1 (true )
355+ protocols .SetHTTP2 (true )
356+ self .Server = http.Server {
357+ Handler : self ,
358+ TLSConfig : tlsConfig ,
359+ Protocols : protocols ,
360+ }
361+
324362 return self , nil
325363}
326364
327- func (h * PluginShim ) ServeHTTP (w http.ResponseWriter , r * http.Request ) {
365+ func (h * CompatV1Shim ) ServeHTTP (w http.ResponseWriter , r * http.Request ) {
328366 if r .TLS == nil {
329367 http .Error (w , "Must use TLS" , http .StatusUpgradeRequired )
330368 return
@@ -354,7 +392,3 @@ func (h *PluginShim) ServeHTTP(w http.ResponseWriter, r *http.Request) {
354392
355393 http .Error (w , "Virtual host not found" , http .StatusNotFound )
356394}
357-
358- func (h * PluginShim ) Serve (listener net.Listener ) error {
359- return h .pluginServer .Serve (listener )
360- }
0 commit comments