-
Notifications
You must be signed in to change notification settings - Fork 2
plugin v2 preview #10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
Signed-off-by: eternal-flame-AD <[email protected]>
Signed-off-by: eternal-flame-AD <[email protected]>
Signed-off-by: eternal-flame-AD <[email protected]>
Signed-off-by: eternal-flame-AD <[email protected]>
ec70e6e
to
e6fc00f
Compare
Signed-off-by: eternal-flame-AD <[email protected]>
Signed-off-by: eternal-flame-AD <[email protected]>
Signed-off-by: eternal-flame-AD <[email protected]>
Signed-off-by: eternal-flame-AD <[email protected]>
Signed-off-by: eternal-flame-AD <[email protected]>
Signed-off-by: eternal-flame-AD <[email protected]>
Signed-off-by: eternal-flame-AD <[email protected]>
Signed-off-by: eternal-flame-AD <[email protected]>
Signed-off-by: eternal-flame-AD <[email protected]>
Signed-off-by: eternal-flame-AD <[email protected]>
Signed-off-by: eternal-flame-AD <[email protected]>
Signed-off-by: eternal-flame-AD <[email protected]>
Signed-off-by: eternal-flame-AD <[email protected]>
@jmattheis Can you take a look when you have time before I do the server side integration? I think basic functionality and consistency tests should be all there. |
on: | ||
push: | ||
branches: | ||
- main |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This project doesn't have a main
branch, only a master
branch. Could you change this to push & pull_request, so that possible contributions are tested too?
flagSet.StringVar(&kexReqFileName, "kex-req-file", "", "File name for the key exchange for Transport Auth. /proc/self/fd/* can be used to open a file descriptor cross platform.") | ||
flagSet.StringVar(&kexRespFileName, "kex-resp-file", "", "File name for the key exchange for Transport Auth. /proc/self/fd/* can be used to open a file descriptor cross platform.") | ||
flagSet.BoolVar(&debug, "debug", false, "Enable debug mode.") | ||
flagSet.Parse(args) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This returns an error, please check/return it.
if err != nil { | ||
return nil, err | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't this already checked?
if err != nil { | ||
return nil, err | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you move this one line up, after the creation of err
? Is also done above for keyReqFile
if err == io.EOF { | ||
break | ||
} | ||
panic(err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use t.Fatal() instead, there are multiple panic calls in the tests.
|
||
tlsWebhookName := transport.BuildPluginTLSName(transport.PurposePluginWebhook, pluginInfo.ModulePath) | ||
|
||
for range 3 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test is difficult to read and IMO a little weird. The webhook is called 8x3 times, but I guess the later ones aren't counted because of the graceful shut down that is also called 8 times. Could we do this without the for loops and explicitly recv the messages. E.g.
// for each capability
msg, err := stream.Recv()
require.NoError(t, err)
require.Equal(t, protobuf.InstanceUpdate_Capable{}, msg.Update)
msg, err := stream.Recv()
require.NoError(t, err)
require.Equal(t, protobuf.InstanceUpdate_Capable{}, msg.Update)
msg, err = stream.Recv()
require.NoError(t, err)
require.Equal(t, protobuf.InstanceUpdate_Capable{}, msg.Update)
displayerClient := protobuf.NewDisplayerClient(rpcClient)
displayResponse, err := displayerClient.Display(context.Background(), &protobuf.DisplayRequest{
User: &protobuf.UserContext{
Id: uint64(testUser.ID),
Name: testUser.Name,
Admin: testUser.Admin,
},
Location: "https://gotify.example.com/",
})
require.NoError(t, err)
require.Equal(t, displayResponse.GetMarkdown(), "...")
tlsWebhookName := transport.BuildPluginTLSName(transport.PurposePluginWebhook, pluginInfo.ModulePath)
// first request
testreq := httptest.NewRequest("GET", "https://"+tlsWebhookName+"/plugin/echo-test/echo", nil)
recorder := httptest.NewRecorder()
compatV1.ServeHTTP(recorder, testreq)
// ...
msg, err = stream.Recv()
require.NoError(t, err)
require.Equal(t, protobuf.InstanceUpdate_Storage{}, msg.Update)
msg, err = stream.Recv()
require.NoError(t, err)
require.Equal(t, protobuf.InstanceUpdate_Message{}, msg.Update)
// second request
testreq := httptest.NewRequest("GET", "https://"+tlsWebhookName+"/plugin/echo-test/echo", nil)
recorder := httptest.NewRecorder()
compatV1.ServeHTTP(recorder, testreq)
// ...
msg, err = stream.Recv()
require.NoError(t, err)
require.Equal(t, protobuf.InstanceUpdate_Storage{}, msg.Update)
msg, err = stream.Recv()
require.NoError(t, err)
require.Equal(t, protobuf.InstanceUpdate_Message{}, msg.Update)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess this is more or less a sanity check of "plugins built on older plugin architecture/mental model will continue to work" by moving the current tested plugins here.
This package is still largely only supportive code, schemas and prototypes for implementing a plugin, so I think a behavioral test is okay.
@@ -0,0 +1,35 @@ | |||
package main |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This PR only supports running the plugins via the shim? Are you planning to support a new way with a func main implementation, so that we don't have to use plugin.Open?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, currently the only end-to-end ones are through shims. The gRPC protocols I think already defined what you need to support to be accepted as a plugin (and largely it's behavior, I know we need a formal documentation but I think we can do it just before finalizing everything.
I am trying to not build too much excess abstraction on top of gRPC to enable people to write plugins in any language easily. I would personally be happy with going with the duck typing model by just saying "implement this gRPC server and key exchange behavior and it is a plugin: a Python script will work too":
at the end the documentation will say something like "Gotify will call your program with these arguments, you are supposed to respond like this ... and if it does that it is a plugin-regardless of how it is implemented. We have the plugin-api package with pre-built schemas but you are welcome to use protoc files in another language"
s.shim.mu.RLock() | ||
instance, ok := s.shim.instances[req.User.Id] | ||
s.shim.mu.RUnlock() | ||
if !ok { | ||
return nil, errors.New("instance not found") | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could be extracted into a method e.g. instance, err := s.getInstance(req.user.id)
} | ||
|
||
func (h *shimV1StorageHandler) Save(b []byte) error { | ||
h.currentStorage = slices.Clone(b) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we get race-conditions here? I'm not sure if we allow running Save/Load in different threads/goroutines.
very much WIP, expect big changes as I go.
Just sharing to get some early opinions.
TODO: