{"id":22105060,"url":"https://github.com/tilotech/go-plugin","last_synced_at":"2025-03-24T02:44:22.153Z","repository":{"id":131917942,"uuid":"465724092","full_name":"tilotech/go-plugin","owner":"tilotech","description":"A golang plugin mechanism that works on lambda!","archived":false,"fork":false,"pushed_at":"2023-05-02T14:19:36.000Z","size":187,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-01-29T08:44:36.549Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tilotech.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-03-03T13:10:33.000Z","updated_at":"2022-03-04T08:45:51.000Z","dependencies_parsed_at":null,"dependency_job_id":"5f9ddcd6-f2ec-4f38-94e5-93e1b32a185e","html_url":"https://github.com/tilotech/go-plugin","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tilotech%2Fgo-plugin","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tilotech%2Fgo-plugin/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tilotech%2Fgo-plugin/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tilotech%2Fgo-plugin/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tilotech","download_url":"https://codeload.github.com/tilotech/go-plugin/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245200675,"owners_count":20576673,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-12-01T06:37:57.080Z","updated_at":"2025-03-24T02:44:22.135Z","avatar_url":"https://github.com/tilotech.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# go-plugin\n\nA simple and fast plugin library for golang based on http over unix socket.\n\nThe biggest advantage of the library is, that you don't need to worry about\nreconnecting to the plugin if a connection is lost. It will automatically handle\nthat for you, which makes it ideal for environments where you might not have so\nmany control over, e.g. serverless functions like AWS Lambda.\n\n## How to use it?\n\nCreate your interface:\n\n```go\npackage api\n\ntype Modifier interface{\n  Modify(s string) (string, error)\n}\n```\n\nWe just defined a simple interface accepting a string and returning a string and\nan error. Maybe an implementation for `Modify` could be a simple string\ndecorator. We'll figure that out later.\n\nAlso don't worry, the example works with just a single parameter, but multiple\nones are also possible.\n\nNext we need a plugin proxy. The proxy will implement the `Modifier` interface,\nbut will forward all calls to the plugin implementation via http over unix\nsockets.\n\n```go\npackage api\n\nimport (\n  \"context\"\n  \"fmt\"\n  \"os\"\n\n  \"github.com/tilotech/go-plugin\"\n)\n\n// The proxy is not exported in this example to show that this is indeed just\n// implementing the Modifier interface. See the Connect function further down\n// to see how it is used.\ntype proxy struct {\n  client *plugin.Client\n}\n\nconst modifyMethod = \"/modify\"\n\nfunc (p *proxy) Modify(s string) (string, error) {\n  // define response structure to automatically unmarshal the response\n  response := \"\"\n  // you can also use an existing context if your interface accepts it\n  ctx := context.Background()\n  // make sure to provide a pointer to the response, otherwise it will not be\n  // modified\n  err := p.client.Call(ctx, modifyMethod, s, \u0026response)\n  return *response, err\n}\n\n// Connect will be used by the plugin consumer for initializing the plugin.\nfunc Connect(starter plugin.Starter, config *pluginConfig) (Modifier, plugin.TermFunc, error) {\n  // we have chosen a static path to the socket here (/tmp/modify), but you can also use a random one\n  client, term, err := plugin.Start(starter, fmt.Sprintf(\"%v/modify\", os.TempDir()), config)\n  if err != nil {\n    return nil, nil, err\n  }\n  return \u0026proxy{\n    client: client,\n  }, term, nil\n}\n```\n\nThe `Connect` function will later be the entry point for using any plugin. The\nstarter that needs to be provided comes currently in two flavours: a starter\nthat will run an executable (intended for the actual plugin) and one that works\ndirectly with a plugin provider (intended for usage from within tests).\n\nNow we need to create the plugin provider. The plugin provider helps to create\nthe actual plugin later. However, while we recommend the usage of a plugin\nprovider, you don't need to create one if the plugins will not be written in go.\nIt's slightly more difficult in that case though.\n\n```go\npackage api\n\nimport (\n  \"context\"\n  \"fmt\"\n\n  \"github.com/tilotech/go-plugin\"\n)\n\n// The provider also is not exported to show which interface it actually implements.\ntype provider struct {\n  impl Modifier\n}\n\nfunc (p *provider) Provide(method string) (plugin.RequestParameter, plugin.InvokeFunc, error) {\n  switch method {\n  case modifyMethod:\n    request := \"\"\n    return \u0026request, p.Modify, nil\n  // add further methods here\n  }\n  return nil, nil, fmt.Errorf(\"invalid method %v\", method)\n}\n\n// Modify will be invoked once the request has been unmarshaled.\nfunc (p *provider) Modify(_ context.Context, params plugin.RequestParameter) (interface{}, error) {\n  // It is guaranteed, that params is of the same type as the first return value\n  // from the Provide method. Asserting the type can safely be done without\n  // worrying about a panic.\n  s := params.(*string)\n  return p.impl.Modify(*s)\n}\n\n// Provide can be used by the plugin author to create the server.\nfunc Provide(impl Modifier) plugin.Provider {\n  return \u0026provider{\n    impl: impl,\n  }\n}\n```\n\nNow we have everything ready to create the actual plugin. This is the only part\nthe plugin authors have to take care of.\n\nNote, that this should be in a different package if you want to provide this as\na binary.\n\n```go\npackage main\n\nimport (\n  \"fmt\"\n\n  \"github.com/tilotech/go-plugin\"\n  \"myproject/api\"\n)\n\nfunc main() {\n  err := plugin.ListenAndServe(api.Provide(\u0026decorateModifierPlugin{}))\n  if err != nil {\n    fmt.Println(err)\n  }\n}\n\ntype decorateModifierPlugin struct {}\n\nfunc (d *decorateModifierPlugin) Modify(s string) (string, error) {\n  return s + \" decorated\"\n}\n```\n\nYou can then compile the plugin using `go build main.go`.\n\nUsing the plugin is also simple.\n\n```go\nmodifier, term, err := api.Connect(plugin.StartWithCmd(\n  func() *exec.Cmd {\n    return exec.Command(\"path/to/plugin\")\n  },\n  plugin.DefaultConfig\n))\nif err != nil {\n  panic(err)\n}\ndefer term()\n\nmodified, err := modifier.Modify(\"some value\")\nfmt.Println(modified, err)\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftilotech%2Fgo-plugin","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftilotech%2Fgo-plugin","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftilotech%2Fgo-plugin/lists"}