[
  {
    "path": ".github/workflows/go.yml",
    "content": "name: Go\n\non:\n  workflow_dispatch:\n  push:\n    branches: [main, master]\n    tags: '*'\n  pull_request:\n    branches: '**'\n\njobs:\n  test:\n    runs-on: ${{ matrix.os }}\n    strategy:\n      matrix:\n        os:\n          - ubuntu-latest\n          - macos-latest\n    steps:\n      - uses: actions/checkout@v3\n\n      - name: Set up Go\n        uses: actions/setup-go@v4\n        with:\n          go-version-file: 'go.mod'\n\n      - name: Test\n        run: go test -v --race --cover ./...\n"
  },
  {
    "path": ".gitignore",
    "content": "# Example binaries\nexample_*\n\n# Glide vendor directory\nvendor/\n\n## From https://github.com/github/gitignore/blob/master/Go.gitignore ##\n\n# Binaries for programs and plugins\n*.exe\n*.dll\n*.so\n*.dylib\n\n# Test binary, build with `go test -c`\n*.test\n\n# Output of the go coverage tool, specifically when used with LiteIDE\n*.out\n\n# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736\n.glide/"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "## Code of Conduct\n\n### Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.\n\n### Our Standards\n\nExamples of behavior that contributes to creating a positive environment\ninclude:\n\n- Using welcoming and inclusive language\n- Being respectful of differing viewpoints and experiences\n- Gracefully accepting constructive criticism\n- Focusing on what is best for the community\n- Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n- The use of sexualized language or imagery and unwelcome sexual attention or advances\n- Trolling, insulting/derogatory comments, and personal or political attacks\n- Public or private harassment\n- Publishing others' private information, such as a physical or electronic address, without explicit permission\n- Other conduct which could reasonably be considered inappropriate in a professional setting\n\n### Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.\n\n### Scope\n\nThis Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.\n\n### Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at hello@kolide.co. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.\n\n### Attribution\n\nThis Code of Conduct is adapted from the Contributor Covenant, version 1.4, available at http://contributor-covenant.org/version/1/4.\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright 2017 Kolide Inc.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."
  },
  {
    "path": "Makefile",
    "content": "PATH := $(GOPATH)/bin:$(PATH)\nexport GO111MODULE=on\n\nall: gen examples\n\ngo-mod-check:\n\t@go help mod > /dev/null || (echo \"Your go is too old, no modules. Seek help.\" && exit 1)\n\ngo-mod-download:\n\tgo mod download\n\ndeps-go: go-mod-check go-mod-download\n\ndeps: deps-go\n\ngen: ./osquery.thrift\n\tmkdir -p ./gen\n\tthrift --gen go:package_prefix=github.com/osquery/osquery-go/gen/ -out ./gen ./osquery.thrift\n\trm -rf gen/osquery/extension-remote gen/osquery/extension_manager-remote\n\tgofmt -w ./gen\n\nexamples: example_query example_call example_logger example_distributed example_table example_config\n\nexample_query: examples/query/*.go\n\tgo build -o example_query ./examples/query/*.go\n\nexample_call: examples/call/*.go\n\tgo build -o example_call ./examples/call/*.go\n\nexample_logger: examples/logger/*.go\n\tgo build -o example_logger.ext  ./examples/logger/*.go\n\nexample_distributed: examples/distributed/*.go\n\tgo build -o example_distributed.ext  ./examples/distributed/*.go\n\nexample_table: examples/table/*.go\n\tgo build -o example_table ./examples/table/*.go\n\nexample_config: examples/config/*.go\n\tgo build -o example_config ./examples/config/*.go\n\ntest: all\n\tgo test -race -cover ./...\n\nclean:\n\trm -rf ./build ./gen\n\n.PHONY: all\n"
  },
  {
    "path": "README.md",
    "content": "# osquery-go\n\n[![GoDoc](https://godoc.org/github.com/osquery/osquery-go?status.svg)](http://godoc.org/github.com/osquery/osquery-go)\n\n[osquery](https://github.com/facebook/osquery) exposes an operating system as a high-performance relational database. This allows you to write SQL-based queries to explore operating system data. With osquery, SQL tables represent abstract concepts such as running processes, loaded kernel modules, open network connections, browser plugins, hardware events or file hashes.\n\nIf you're interested in learning more about osquery, visit the [GitHub project](https://github.com/facebook/osquery), the [website](https://osquery.io), and the [users guide](https://osquery.readthedocs.io).\n\n## What is osquery-go?\n\nIn osquery, SQL tables, configuration retrieval, log handling, etc. are implemented via a robust plugin and extensions API. This project contains Go bindings for creating osquery extensions in Go. To create an extension, you must create an executable binary which instantiates an `ExtensionManagerServer` and registers the plugins that you would like to be added to osquery. You can then have osquery load the extension in your desired context (ie: in a long running instance of `osqueryd` or during an interactive query session with `osqueryi`). For more information about how this process works at a lower level, see the osquery [wiki](https://osquery.readthedocs.io/en/latest/development/osquery-sdk/).\n\n## Install\n\nThis library is compatible with Go Modules. To install:\n\n``` go\ngo get github.com/osquery/osquery-go\n```\n\n## Using the library\n\n### Creating a new osquery table\n\nIf you want to create a custom osquery table in Go, you'll need to write an extension which registers the implementation of your table. Consider the following Go program:\n\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"log\"\n\t\"os\"\n\t\"flag\"\n\n\t\"github.com/osquery/osquery-go\"\n\t\"github.com/osquery/osquery-go/plugin/table\"\n)\n\nfunc main() {\n\tsocket := flag.String(\"socket\", \"\", \"Path to osquery socket file\")\n\tflag.Parse()\n\tif *socket == \"\" {\n\t\tlog.Fatalf(`Usage: %s --socket SOCKET_PATH`, os.Args[0])\n\t}\n\n\tserver, err := osquery.NewExtensionManagerServer(\"foobar\", *socket)\n\tif err != nil {\n\t\tlog.Fatalf(\"Error creating extension: %s\\n\", err)\n\t}\n\n\t// Create and register a new table plugin with the server.\n\t// table.NewPlugin requires the table plugin name,\n\t// a slice of Columns and a Generate function.\n\tserver.RegisterPlugin(table.NewPlugin(\"foobar\", FoobarColumns(), FoobarGenerate))\n\tif err := server.Run(); err != nil {\n\t\tlog.Fatalln(err)\n\t}\n}\n\n// FoobarColumns returns the columns that our table will return.\nfunc FoobarColumns() []table.ColumnDefinition {\n\treturn []table.ColumnDefinition{\n\t\ttable.TextColumn(\"foo\"),\n\t\ttable.TextColumn(\"baz\"),\n\t}\n}\n\n// FoobarGenerate will be called whenever the table is queried. It should return\n// a full table scan.\nfunc FoobarGenerate(ctx context.Context, queryContext table.QueryContext) ([]map[string]string, error) {\n\treturn []map[string]string{\n\t\t{\n\t\t\t\"foo\": \"bar\",\n\t\t\t\"baz\": \"baz\",\n\t\t},\n\t\t{\n\t\t\t\"foo\": \"bar\",\n\t\t\t\"baz\": \"baz\",\n\t\t},\n\t}, nil\n}\n```\n\nTo test this code, start an osquery shell and find the path of the osquery extension socket:\n\n```sql\nosqueryi --nodisable_extensions\nosquery> select value from osquery_flags where name = 'extensions_socket';\n+-----------------------------------+\n| value                             |\n+-----------------------------------+\n| /Users/USERNAME/.osquery/shell.em |\n+-----------------------------------+\n```\n\nThen start the Go extension and have it communicate with osqueryi via the extension socket that you retrieved above:\n\n```bash\ngo run ./my_table_plugin.go --socket /Users/USERNAME/.osquery/shell.em\n```\n\nAlternatively, you can also autoload your extension when starting an osquery shell:\n\n```bash\ngo build -o my_table_plugin my_table_plugin.go\nosqueryi --extension /path/to/my_table_plugin\n```\n\nThis will register a table called \"foobar\". As you can see, the table will return two rows:\n\n```sql\nosquery> select * from foobar;\n+-----+-----+\n| foo | baz |\n+-----+-----+\n| bar | baz |\n| bar | baz |\n+-----+-----+\nosquery>\n```\n\nThis is obviously a contrived example, but it's easy to imagine the possibilities.\n\nUsing the instructions found on the [wiki](https://osquery.readthedocs.io/en/latest/development/osquery-sdk/), you can deploy your extension with an existing osquery deployment.\n\n### Creating logger and config plugins\n\nThe process required to create a config and/or logger plugin is very similar to the process outlined above for creating an osquery table. Specifically, you would create an `ExtensionManagerServer` instance in `func main()`, register your plugin and launch the extension as described above. The only difference is that the implementation of your plugin would be different. Each plugin package has a `NewPlugin` function which takes the plugin name as the first argument, followed by a list of required arguments to implement the plugin.\nFor example, consider the implementation of an example logger plugin:\n\n```go\nfunc main() {\n    // create and register the plugin\n\tserver.RegisterPlugin(logger.NewPlugin(\"example_logger\", LogString))\n}\n\nfunc LogString(ctx context.Context, typ logger.LogType, logText string) error {\n\tlog.Printf(\"%s: %s\\n\", typ, logText)\n\treturn nil\n}\n```\n\nAdditionally, consider the implementation of an example config plugin:\n\n```go\nfunc main() {\n    // create and register the plugin\n\tserver.RegisterPlugin(config.NewPlugin(\"example\", GenerateConfigs))\n}\n\nfunc GenerateConfigs(ctx context.Context) (map[string]string, error) {\n\treturn map[string]string{\n\t\t\"config1\": `\n{\n  \"options\": {\n    \"host_identifier\": \"hostname\",\n    \"schedule_splay_percent\": 10\n  },\n  \"schedule\": {\n    \"macos_kextstat\": {\n      \"query\": \"SELECT * FROM kernel_extensions;\",\n      \"interval\": 10\n    },\n    \"foobar\": {\n      \"query\": \"SELECT foo, bar, pid FROM foobar_table;\",\n      \"interval\": 600\n    }\n  }\n}\n`,\n\t}, nil\n}\n```\n\nAll of these examples and more can be found in the [examples](./examples) subdirectory of this repository.\n\n### Execute queries in Go\n\nThis library can also be used to create a Go client for the osqueryd or osqueryi's extension socket. You can use this to add the ability to performantly execute osquery queries to your Go program. Consider the following example:\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/osquery/osquery-go\"\n)\n\nfunc main() {\n\tif len(os.Args) != 3 {\n\t\tlog.Fatalf(\"Usage: %s SOCKET_PATH QUERY\", os.Args[0])\n\t}\n\n\tclient, err := osquery.NewClient(os.Args[1], 10*time.Second)\n\tif err != nil {\n\t\tlog.Fatalf(\"Error creating Thrift client: %v\", err)\n\t}\n\tdefer client.Close()\n\n\tresp, err := client.Query(os.Args[2])\n\tif err != nil {\n\t\tlog.Fatalf(\"Error communicating with osqueryd: %v\",err)\n\t}\n\tif resp.Status.Code != 0 {\n\t\tlog.Fatalf(\"osqueryd returned error: %s\", resp.Status.Message)\n\t}\n\n\tfmt.Printf(\"Got results:\\n%#v\\n\", resp.Response)\n}\n```\n\n### Loading extensions with osqueryd\n\nIf you write an extension with a logger or config plugin, you'll likely want to autoload the extensions when `osqueryd` starts. `osqueryd` has a few requirements for autoloading extensions, documented on the [wiki](https://osquery.readthedocs.io/en/latest/deployment/extensions/). Here's a quick example using a logging plugin to get you started:\n\n1. Build the plugin. Make sure to add `.ext` as the file extension. It is required by osqueryd.\n```go build -o /usr/local/osquery_extensions/my_logger.ext```\n\n2. Set the correct permissions on the file and directory. If `osqueryd` runs as root, the directory for the extension must only be writable by root.\n\n```\nsudo chown -R root /usr/local/osquery_extensions/\n```\n\n3. Create an `extensions.load` file with the path of your extension.\n\n```\necho \"/usr/local/osquery_extensions/my_logger.ext\" > /tmp/extensions.load\n```\n\n4. Start `osqueryd` with the `--extensions_autoload` flag.\n\n```\nsudo osqueryd --extensions_autoload=/tmp/extensions.load --logger-plugin=my_logger -verbose\n```\n\n\n## Contributing\n\nFor more information on contributing to this project, see [CONTRIBUTING.md](./CONTRIBUTING.md).\n\n## Vulnerabilities\n\nIf you find a vulnerability in this software, please email [security@kolide.co](mailto:security@kolide.co).\n"
  },
  {
    "path": "client.go",
    "content": "package osquery\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"github.com/osquery/osquery-go/gen/osquery\"\n\t\"github.com/osquery/osquery-go/traces\"\n\t\"github.com/osquery/osquery-go/transport\"\n\n\t\"github.com/apache/thrift/lib/go/thrift\"\n\t\"github.com/pkg/errors\"\n)\n\nconst (\n\tdefaultWaitTime    = 200 * time.Millisecond\n\tdefaultMaxWaitTime = 1 * time.Minute\n)\n\n// ExtensionManagerClient is a wrapper for the osquery Thrift extensions API.\ntype ExtensionManagerClient struct {\n\tclient    osquery.ExtensionManager\n\ttransport thrift.TTransport\n\n\twaitTime    time.Duration\n\tmaxWaitTime time.Duration\n\tlock        *locker\n}\n\ntype ClientOption func(*ExtensionManagerClient)\n\n// WaitTime sets the default amount of wait time for the osquery socket to free up. You can override this on a per\n// call basis by setting a context deadline\nfunc DefaultWaitTime(d time.Duration) ClientOption {\n\treturn func(c *ExtensionManagerClient) {\n\t\tc.waitTime = d\n\t}\n}\n\n// MaxWaitTime is the maximum amount of time something is allowed to wait for the osquery socket. This takes precedence\n// over the context deadline.\nfunc MaxWaitTime(d time.Duration) ClientOption {\n\treturn func(c *ExtensionManagerClient) {\n\t\tc.maxWaitTime = d\n\t}\n}\n\n// NewClient creates a new client communicating to osquery over the socket at\n// the provided path. If resolving the address or connecting to the socket\n// fails, this function will error.\nfunc NewClient(path string, socketOpenTimeout time.Duration, opts ...ClientOption) (*ExtensionManagerClient, error) {\n\tc := &ExtensionManagerClient{\n\t\twaitTime:    defaultWaitTime,\n\t\tmaxWaitTime: defaultMaxWaitTime,\n\t}\n\n\tfor _, opt := range opts {\n\t\topt(c)\n\t}\n\n\tif c.waitTime > c.maxWaitTime {\n\t\treturn nil, errors.New(\"default wait time larger than max wait time\")\n\t}\n\n\tc.lock = NewLocker(c.waitTime, c.maxWaitTime)\n\n\tif c.client == nil {\n\t\ttrans, err := transport.Open(path, socketOpenTimeout)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tc.transport = trans\n\t\tc.client = osquery.NewExtensionManagerClientFactory(\n\t\t\ttrans,\n\t\t\tthrift.NewTBinaryProtocolFactoryDefault(),\n\t\t)\n\t}\n\n\treturn c, nil\n}\n\n// Close should be called to close the transport when use of the client is\n// completed.\nfunc (c *ExtensionManagerClient) Close() {\n\tif c.transport != nil && c.transport.IsOpen() {\n\t\tc.transport.Close()\n\t}\n}\n\n// Ping requests metadata from the extension manager, using a new background context\nfunc (c *ExtensionManagerClient) Ping() (*osquery.ExtensionStatus, error) {\n\treturn c.PingContext(context.Background())\n}\n\n// PingContext requests metadata from the extension manager.\nfunc (c *ExtensionManagerClient) PingContext(ctx context.Context) (*osquery.ExtensionStatus, error) {\n\tif err := c.lock.Lock(ctx); err != nil {\n\t\treturn nil, err\n\t}\n\tdefer c.lock.Unlock()\n\treturn c.client.Ping(ctx)\n}\n\n// Call requests a call to an extension (or core) registry plugin, using a new background context\nfunc (c *ExtensionManagerClient) Call(registry, item string, request osquery.ExtensionPluginRequest) (*osquery.ExtensionResponse, error) {\n\treturn c.CallContext(context.Background(), registry, item, request)\n}\n\n// CallContext requests a call to an extension (or core) registry plugin.\nfunc (c *ExtensionManagerClient) CallContext(ctx context.Context, registry, item string, request osquery.ExtensionPluginRequest) (*osquery.ExtensionResponse, error) {\n\tctx, span := traces.StartSpan(ctx, \"ExtensionManagerClient.CallContext\")\n\tdefer span.End()\n\n\tif err := c.lock.Lock(ctx); err != nil {\n\t\treturn nil, err\n\t}\n\tdefer c.lock.Unlock()\n\treturn c.client.Call(ctx, registry, item, request)\n}\n\n// Extensions requests the list of active registered extensions, using a new background context\nfunc (c *ExtensionManagerClient) Extensions() (osquery.InternalExtensionList, error) {\n\treturn c.ExtensionsContext(context.Background())\n}\n\n// ExtensionsContext requests the list of active registered extensions.\nfunc (c *ExtensionManagerClient) ExtensionsContext(ctx context.Context) (osquery.InternalExtensionList, error) {\n\tctx, span := traces.StartSpan(ctx, \"ExtensionManagerClient.ExtensionsContext\")\n\tdefer span.End()\n\n\tif err := c.lock.Lock(ctx); err != nil {\n\t\treturn nil, err\n\t}\n\tdefer c.lock.Unlock()\n\treturn c.client.Extensions(ctx)\n}\n\n// RegisterExtension registers the extension plugins with the osquery process, using a new background context\nfunc (c *ExtensionManagerClient) RegisterExtension(info *osquery.InternalExtensionInfo, registry osquery.ExtensionRegistry) (*osquery.ExtensionStatus, error) {\n\treturn c.RegisterExtensionContext(context.Background(), info, registry)\n}\n\n// RegisterExtensionContext registers the extension plugins with the osquery process.\nfunc (c *ExtensionManagerClient) RegisterExtensionContext(ctx context.Context, info *osquery.InternalExtensionInfo, registry osquery.ExtensionRegistry) (*osquery.ExtensionStatus, error) {\n\tctx, span := traces.StartSpan(ctx, \"ExtensionManagerClient.RegisterExtensionContext\")\n\tdefer span.End()\n\n\tif err := c.lock.Lock(ctx); err != nil {\n\t\treturn nil, err\n\t}\n\tdefer c.lock.Unlock()\n\treturn c.client.RegisterExtension(ctx, info, registry)\n}\n\n// DeregisterExtension de-registers the extension plugins with the osquery process, using a new background context\nfunc (c *ExtensionManagerClient) DeregisterExtension(uuid osquery.ExtensionRouteUUID) (*osquery.ExtensionStatus, error) {\n\treturn c.DeregisterExtensionContext(context.Background(), uuid)\n}\n\n// DeregisterExtensionContext de-registers the extension plugins with the osquery process.\nfunc (c *ExtensionManagerClient) DeregisterExtensionContext(ctx context.Context, uuid osquery.ExtensionRouteUUID) (*osquery.ExtensionStatus, error) {\n\tctx, span := traces.StartSpan(ctx, \"ExtensionManagerClient.DeregisterExtensionContext\")\n\tdefer span.End()\n\n\tif err := c.lock.Lock(ctx); err != nil {\n\t\treturn nil, err\n\t}\n\tdefer c.lock.Unlock()\n\treturn c.client.DeregisterExtension(ctx, uuid)\n}\n\n// Options requests the list of bootstrap or configuration options, using a new background context.\nfunc (c *ExtensionManagerClient) Options() (osquery.InternalOptionList, error) {\n\treturn c.OptionsContext(context.Background())\n}\n\n// OptionsContext requests the list of bootstrap or configuration options.\nfunc (c *ExtensionManagerClient) OptionsContext(ctx context.Context) (osquery.InternalOptionList, error) {\n\tctx, span := traces.StartSpan(ctx, \"ExtensionManagerClient.OptionsContext\")\n\tdefer span.End()\n\n\tif err := c.lock.Lock(ctx); err != nil {\n\t\treturn nil, err\n\t}\n\tdefer c.lock.Unlock()\n\treturn c.client.Options(ctx)\n}\n\n// Query requests a query to be run and returns the extension\n// response, using a new background context.  Consider using the\n// QueryRow or QueryRows helpers for a more friendly interface.\nfunc (c *ExtensionManagerClient) Query(sql string) (*osquery.ExtensionResponse, error) {\n\treturn c.QueryContext(context.Background(), sql)\n}\n\n// QueryContext requests a query to be run and returns the extension response.\n// Consider using the QueryRow or QueryRows helpers for a more friendly\n// interface.\nfunc (c *ExtensionManagerClient) QueryContext(ctx context.Context, sql string) (*osquery.ExtensionResponse, error) {\n\tctx, span := traces.StartSpan(ctx, \"ExtensionManagerClient.QueryContext\")\n\tdefer span.End()\n\n\tif err := c.lock.Lock(ctx); err != nil {\n\t\treturn nil, err\n\t}\n\tdefer c.lock.Unlock()\n\treturn c.client.Query(ctx, sql)\n}\n\n// QueryRows is a helper that executes the requested query and returns the\n// results. It handles checking both the transport level errors and the osquery\n// internal errors by returning a normal Go error type.\nfunc (c *ExtensionManagerClient) QueryRows(sql string) ([]map[string]string, error) {\n\treturn c.QueryRowsContext(context.Background(), sql)\n}\n\n// QueryRowsContext is a helper that executes the requested query and returns the\n// results. It handles checking both the transport level errors and the osquery\n// internal errors by returning a normal Go error type.\nfunc (c *ExtensionManagerClient) QueryRowsContext(ctx context.Context, sql string) ([]map[string]string, error) {\n\tctx, span := traces.StartSpan(ctx, \"ExtensionManagerClient.QueryRowsContext\")\n\tdefer span.End()\n\n\tres, err := c.QueryContext(ctx, sql)\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"transport error in query\")\n\t}\n\tif res.Status == nil {\n\t\treturn nil, errors.New(\"query returned nil status\")\n\t}\n\tif res.Status.Code != 0 {\n\t\treturn nil, errors.Errorf(\"query returned error: %s\", res.Status.Message)\n\t}\n\treturn res.Response, nil\n\n}\n\n// QueryRow behaves similarly to QueryRows, but it returns an error if the\n// query does not return exactly one row.\nfunc (c *ExtensionManagerClient) QueryRow(sql string) (map[string]string, error) {\n\treturn c.QueryRowContext(context.Background(), sql)\n}\n\n// QueryRowContext behaves similarly to QueryRows, but it returns an error if the\n// query does not return exactly one row.\nfunc (c *ExtensionManagerClient) QueryRowContext(ctx context.Context, sql string) (map[string]string, error) {\n\tctx, span := traces.StartSpan(ctx, \"ExtensionManagerClient.QueryRowContext\")\n\tdefer span.End()\n\n\tres, err := c.QueryRowsContext(ctx, sql)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif len(res) != 1 {\n\t\treturn nil, errors.Errorf(\"expected 1 row, got %d\", len(res))\n\t}\n\treturn res[0], nil\n}\n\n// GetQueryColumns requests the columns returned by the parsed query, using a new background context.\nfunc (c *ExtensionManagerClient) GetQueryColumns(sql string) (*osquery.ExtensionResponse, error) {\n\treturn c.GetQueryColumnsContext(context.Background(), sql)\n}\n\n// GetQueryColumnsContext requests the columns returned by the parsed query.\nfunc (c *ExtensionManagerClient) GetQueryColumnsContext(ctx context.Context, sql string) (*osquery.ExtensionResponse, error) {\n\tctx, span := traces.StartSpan(ctx, \"ExtensionManagerClient.GetQueryColumnsContext\")\n\tdefer span.End()\n\n\tif err := c.lock.Lock(ctx); err != nil {\n\t\treturn nil, err\n\t}\n\tdefer c.lock.Unlock()\n\treturn c.client.GetQueryColumns(ctx, sql)\n}\n"
  },
  {
    "path": "client_test.go",
    "content": "package osquery\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/osquery/osquery-go/gen/osquery\"\n\t\"github.com/osquery/osquery-go/mock\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestQueryRows(t *testing.T) {\n\tt.Parallel()\n\tmock := &mock.ExtensionManager{}\n\tclient, err := NewClient(\"\", 5*time.Second, WithOsqueryThriftClient(mock))\n\trequire.NoError(t, err)\n\n\t// Transport related error\n\tmock.QueryFunc = func(ctx context.Context, sql string) (*osquery.ExtensionResponse, error) {\n\t\treturn nil, errors.New(\"boom!\")\n\t}\n\trows, err := client.QueryRows(\"select 1\")\n\tassert.NotNil(t, err)\n\trow, err := client.QueryRow(\"select 1\")\n\tassert.NotNil(t, err)\n\n\t// Nil status\n\tmock.QueryFunc = func(ctx context.Context, sql string) (*osquery.ExtensionResponse, error) {\n\t\treturn &osquery.ExtensionResponse{}, nil\n\t}\n\trows, err = client.QueryRows(\"select 1\")\n\tassert.NotNil(t, err)\n\trow, err = client.QueryRow(\"select 1\")\n\tassert.NotNil(t, err)\n\n\t// Query error\n\tmock.QueryFunc = func(ctx context.Context, sql string) (*osquery.ExtensionResponse, error) {\n\t\treturn &osquery.ExtensionResponse{\n\t\t\tStatus: &osquery.ExtensionStatus{Code: 1, Message: \"bad query\"},\n\t\t}, nil\n\t}\n\trows, err = client.QueryRows(\"select bad query\")\n\tassert.NotNil(t, err)\n\trow, err = client.QueryRow(\"select bad query\")\n\tassert.NotNil(t, err)\n\n\t// Good query (one row)\n\texpectedRows := []map[string]string{\n\t\t{\"1\": \"1\"},\n\t}\n\tmock.QueryFunc = func(ctx context.Context, sql string) (*osquery.ExtensionResponse, error) {\n\t\treturn &osquery.ExtensionResponse{\n\t\t\tStatus:   &osquery.ExtensionStatus{Code: 0, Message: \"OK\"},\n\t\t\tResponse: expectedRows,\n\t\t}, nil\n\t}\n\trows, err = client.QueryRows(\"select 1\")\n\tassert.Nil(t, err)\n\tassert.Equal(t, expectedRows, rows)\n\trow, err = client.QueryRow(\"select 1\")\n\tassert.Nil(t, err)\n\tassert.Equal(t, expectedRows[0], row)\n\n\t// Good query (multiple rows)\n\texpectedRows = []map[string]string{\n\t\t{\"1\": \"1\"},\n\t\t{\"1\": \"2\"},\n\t}\n\tmock.QueryFunc = func(ctx context.Context, sql string) (*osquery.ExtensionResponse, error) {\n\t\treturn &osquery.ExtensionResponse{\n\t\t\tStatus:   &osquery.ExtensionStatus{Code: 0, Message: \"OK\"},\n\t\t\tResponse: expectedRows,\n\t\t}, nil\n\t}\n\trows, err = client.QueryRows(\"select 1 union select 2\")\n\tassert.Nil(t, err)\n\tassert.Equal(t, expectedRows, rows)\n\trow, err = client.QueryRow(\"select 1 union select 2\")\n\tassert.NotNil(t, err)\n}\n\n// TestLocking tests the the client correctly locks access to the osquery socket. Thrift only supports a single\n// actor on the socket at a time, this means that in parallel go code, it's very easy to have messages get\n// crossed and generate errors. This tests to ensure the locking works\nfunc TestLocking(t *testing.T) {\n\tt.Parallel()\n\n\tsock := os.Getenv(\"OSQ_SOCKET\")\n\tif sock == \"\" {\n\t\tt.Skip(\"no osquery socket specified\")\n\t}\n\n\tosq, err := NewClient(sock, 5*time.Second)\n\trequire.NoError(t, err)\n\n\t// The issue we're testing is about multithreaded access. Let's hammer on it!\n\twait := sync.WaitGroup{}\n\tfor i := 0; i < 100; i++ {\n\t\twait.Add(1)\n\t\tgo func() {\n\t\t\tdefer wait.Done()\n\n\t\t\tstatus, err := osq.Ping()\n\t\t\trequire.NoError(t, err, \"call to Ping()\")\n\t\t\tif err != nil {\n\t\t\t\trequire.Equal(t, 0, status.Code, fmt.Errorf(\"ping returned %d: %s\", status.Code, status.Message))\n\t\t\t}\n\t\t}()\n\t}\n\n\twait.Wait()\n}\n\nfunc TestLockTimeouts(t *testing.T) {\n\tt.Parallel()\n\tmock := &mock.ExtensionManager{}\n\tclient, err := NewClient(\"\", 5*time.Second, WithOsqueryThriftClient(mock), DefaultWaitTime(100*time.Millisecond), DefaultWaitTime(5*time.Second))\n\trequire.NoError(t, err)\n\n\twait := sync.WaitGroup{}\n\n\terrChan := make(chan error, 10)\n\tfor i := 0; i < 3; i++ {\n\t\twait.Add(1)\n\t\tgo func() {\n\t\t\tdefer wait.Done()\n\n\t\t\tctx, cancel := context.WithTimeout(context.TODO(), 100*time.Millisecond)\n\t\t\tdefer cancel()\n\n\t\t\terrChan <- client.SlowLocker(ctx, 75*time.Millisecond)\n\t\t}()\n\t}\n\n\twait.Wait()\n\tclose(errChan)\n\n\tvar successCount, errCount int\n\tfor err := range errChan {\n\t\tif err == nil {\n\t\t\tsuccessCount += 1\n\t\t} else {\n\t\t\terrCount += 1\n\t\t}\n\t}\n\n\tassert.Equal(t, 2, successCount, \"expected success count\")\n\tassert.Equal(t, 1, errCount, \"expected error count\")\n}\n\n// WithOsqueryThriftClient sets the underlying thrift client. This can be used to set a mock\nfunc WithOsqueryThriftClient(client osquery.ExtensionManager) ClientOption {\n\treturn func(c *ExtensionManagerClient) {\n\t\tc.client = client\n\t}\n}\n\n// SlowLocker attempts to emulate a slow sql routine, so we can test how lock timeouts work.\nfunc (c *ExtensionManagerClient) SlowLocker(ctx context.Context, d time.Duration) error {\n\tif err := c.lock.Lock(ctx); err != nil {\n\t\treturn err\n\t}\n\tdefer c.lock.Unlock()\n\ttime.Sleep(d)\n\treturn nil\n}\n"
  },
  {
    "path": "examples/call/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/osquery/osquery-go\"\n)\n\nfunc main() {\n\tif len(os.Args) != 5 {\n\t\tfmt.Printf(`Usage: %s SOCKET_PATH REGISTRY_NAME PLUGIN_NAME ACTION\n\nCalls the provided action for the plugin with the given registry and plugin\nname.\n`, os.Args[0])\n\t\tos.Exit(1)\n\t}\n\n\tsocketPath := os.Args[1]\n\tregistryName := os.Args[2]\n\tpluginName := os.Args[3]\n\taction := os.Args[4]\n\n\tclient, err := osquery.NewClient(socketPath, 10*time.Second)\n\tif err != nil {\n\t\tfmt.Println(\"Error creating Thrift client: \" + err.Error())\n\t\tos.Exit(1)\n\t}\n\tdefer client.Close()\n\n\tresp, err := client.Call(registryName, pluginName, map[string]string{\"action\": action})\n\tif err != nil {\n\t\tfmt.Println(\"Error communicating with osqueryd: \" + err.Error())\n\t\tos.Exit(1)\n\t}\n\tif resp.Status.Code != 0 {\n\t\tfmt.Println(\"osqueryd returned error: \" + resp.Status.Message)\n\t\tos.Exit(1)\n\t}\n\n\tfmt.Printf(\"Got results:\\n%#v\\n\", resp.Response)\n}\n"
  },
  {
    "path": "examples/config/main.go",
    "content": "package main\n\nimport (\n\t\"context\"\n\t\"flag\"\n\t\"log\"\n\t\"time\"\n\n\t\"github.com/osquery/osquery-go\"\n\t\"github.com/osquery/osquery-go/plugin/config\"\n)\n\nvar (\n\tsocket   = flag.String(\"socket\", \"\", \"Path to the extensions UNIX domain socket\")\n\ttimeout  = flag.Int(\"timeout\", 3, \"Seconds to wait for autoloaded extensions\")\n\tinterval = flag.Int(\"interval\", 3, \"Seconds delay between connectivity checks\")\n)\n\nfunc main() {\n\tflag.Parse()\n\n\tif *socket == \"\" {\n\t\tlog.Fatalln(\"Missing required --socket argument\")\n\t}\n\n\tserverTimeout := osquery.ServerTimeout(\n\t\ttime.Second * time.Duration(*timeout),\n\t)\n\tserverPingInterval := osquery.ServerPingInterval(\n\t\ttime.Second * time.Duration(*interval),\n\t)\n\n\tserver, err := osquery.NewExtensionManagerServer(\n\t\t\"example_extension\",\n\t\t*socket,\n\t\tserverTimeout,\n\t\tserverPingInterval,\n\t)\n\n\tif err != nil {\n\t\tlog.Fatalf(\"Error creating extension: %s\\n\", err)\n\t}\n\tserver.RegisterPlugin(config.NewPlugin(\"example_config\", GenerateConfigs))\n\tif err := server.Run(); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n\nfunc GenerateConfigs(ctx context.Context) (map[string]string, error) {\n\treturn map[string]string{\n\t\t\"config1\": `\n{\n  \"options\": {\n    \"host_identifier\": \"hostname\",\n    \"schedule_splay_percent\": 10\n  },\n  \"schedule\": {\n    \"macos_kextstat\": {\n      \"query\": \"SELECT * FROM kernel_extensions;\",\n      \"interval\": 10\n    },\n    \"foobar\": {\n      \"query\": \"SELECT foo, bar, pid FROM foobar_table;\",\n      \"interval\": 600\n    }\n  }\n}\n`,\n\t}, nil\n}\n"
  },
  {
    "path": "examples/distributed/main.go",
    "content": "package main\n\nimport (\n\t\"context\"\n\t\"flag\"\n\t\"fmt\"\n\t\"log\"\n\n\t\"github.com/osquery/osquery-go\"\n\t\"github.com/osquery/osquery-go/plugin/distributed\"\n)\n\nfunc main() {\n\tsocketPath := flag.String(\"socket\", \"\", \"path to osqueryd extensions socket\")\n\tflag.Int(\"timeout\", 0, \"\")\n\tflag.Int(\"interval\", 0, \"\")\n\tflag.Parse()\n\n\tserver, err := osquery.NewExtensionManagerServer(\"example_distributed\", *socketPath)\n\tif err != nil {\n\t\tlog.Fatalf(\"Error creating extension: %s\\n\", err)\n\t}\n\tserver.RegisterPlugin(distributed.NewPlugin(\"example_distributed\", getQueries, writeResults))\n\tif err := server.Run(); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n\nfunc getQueries(ctx context.Context) (*distributed.GetQueriesResult, error) {\n\treturn &distributed.GetQueriesResult{Queries: map[string]string{\"time\": \"select * from time\"}}, nil\n}\n\nfunc writeResults(ctx context.Context, results []distributed.Result) error {\n\tfmt.Println(results)\n\treturn nil\n}\n"
  },
  {
    "path": "examples/logger/main.go",
    "content": "package main\n\nimport (\n\t\"context\"\n\t\"flag\"\n\t\"log\"\n\n\t\"github.com/osquery/osquery-go\"\n\t\"github.com/osquery/osquery-go/plugin/logger\"\n)\n\nfunc main() {\n\tsocketPath := flag.String(\"socket\", \"\", \"path to osqueryd extensions socket\")\n\tflag.Int(\"timeout\", 0, \"\")\n\tflag.Int(\"interval\", 0, \"\")\n\tflag.Parse()\n\n\tserver, err := osquery.NewExtensionManagerServer(\"example_logger\", *socketPath)\n\tif err != nil {\n\t\tlog.Fatalf(\"Error creating extension: %s\\n\", err)\n\t}\n\tserver.RegisterPlugin(logger.NewPlugin(\"example_logger\", LogString))\n\tif err := server.Run(); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n\nfunc LogString(ctx context.Context, typ logger.LogType, logText string) error {\n\tlog.Printf(\"%s: %s\\n\", typ, logText)\n\treturn nil\n}\n"
  },
  {
    "path": "examples/query/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/osquery/osquery-go\"\n)\n\nfunc main() {\n\tif len(os.Args) != 3 {\n\t\tfmt.Printf(`Usage: %s SOCKET_PATH QUERY\\n\n\nRequests osqueryd to run the provided query and prints the results.\n`, os.Args[0])\n\t\tos.Exit(1)\n\t}\n\n\tclient, err := osquery.NewClient(os.Args[1], 10*time.Second)\n\tif err != nil {\n\t\tfmt.Println(\"Error creating Thrift client: \" + err.Error())\n\t\tos.Exit(1)\n\t}\n\tdefer client.Close()\n\n\tresp, err := client.Query(os.Args[2])\n\tif err != nil {\n\t\tfmt.Println(\"Error communicating with osqueryd: \" + err.Error())\n\t\tos.Exit(1)\n\t}\n\tif resp.Status.Code != 0 {\n\t\tfmt.Println(\"osqueryd returned error: \" + resp.Status.Message)\n\t\tos.Exit(1)\n\t}\n\n\tfmt.Printf(\"Got results:\\n%#v\\n\", resp.Response)\n}\n"
  },
  {
    "path": "examples/table/main.go",
    "content": "package main\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"flag\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/osquery/osquery-go\"\n\t\"github.com/osquery/osquery-go/plugin/table\"\n)\n\nvar (\n\tsocket   = flag.String(\"socket\", \"\", \"Path to the extensions UNIX domain socket\")\n\ttimeout  = flag.Int(\"timeout\", 3, \"Seconds to wait for autoloaded extensions\")\n\tinterval = flag.Int(\"interval\", 3, \"Seconds delay between connectivity checks\")\n\tspec     = flag.Bool(\"spec\", false, \"Don't run as a plugin, instead print the table spec\")\n)\n\nfunc main() {\n\tflag.Parse()\n\n\ttbl := table.NewPlugin(\"example_table\", ExampleColumns(), ExampleGenerate, table.WithDescription(\"A simple example table\"))\n\n\tif *spec {\n\t\ttableSpec, err := json.MarshalIndent(tbl.Spec(), \"\", \"  \")\n\t\tif err != nil {\n\t\t\tlog.Fatalf(\"Error marshalling spec: %s\\n\", err)\n\t\t}\n\n\t\tfmt.Printf(\"%s\\n\", tableSpec)\n\t\tos.Exit(0)\n\t}\n\n\tif *socket == \"\" {\n\t\tlog.Fatalln(\"Missing required --socket argument\")\n\t}\n\tserverTimeout := osquery.ServerTimeout(\n\t\ttime.Second * time.Duration(*timeout),\n\t)\n\tserverPingInterval := osquery.ServerPingInterval(\n\t\ttime.Second * time.Duration(*interval),\n\t)\n\n\tserver, err := osquery.NewExtensionManagerServer(\n\t\t\"example_extension\",\n\t\t*socket,\n\t\tserverTimeout,\n\t\tserverPingInterval,\n\t)\n\n\tif err != nil {\n\t\tlog.Fatalf(\"Error creating extension: %s\\n\", err)\n\t}\n\tserver.RegisterPlugin(tbl)\n\tif err := server.Run(); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n\nfunc ExampleColumns() []table.ColumnDefinition {\n\treturn []table.ColumnDefinition{\n\t\ttable.TextColumn(\"text\", table.ColumnDescription(\"Some text\")),\n\t\ttable.IntegerColumn(\"integer\"),\n\t\ttable.BigIntColumn(\"big_int\"),\n\t\ttable.DoubleColumn(\"double\"),\n\t}\n}\n\nfunc ExampleGenerate(ctx context.Context, queryContext table.QueryContext) ([]map[string]string, error) {\n\treturn []map[string]string{\n\t\t{\n\t\t\t\"text\":    \"hello world\",\n\t\t\t\"integer\": \"123\",\n\t\t\t\"big_int\": \"-1234567890\",\n\t\t\t\"double\":  \"3.14159\",\n\t\t},\n\t}, nil\n}\n"
  },
  {
    "path": "gen/osquery/GoUnusedProtection__.go",
    "content": "// Code generated by Thrift Compiler (0.16.0). DO NOT EDIT.\n\npackage osquery\n\nvar GoUnusedProtection__ int\n"
  },
  {
    "path": "gen/osquery/osquery-consts.go",
    "content": "// Code generated by Thrift Compiler (0.16.0). DO NOT EDIT.\n\npackage osquery\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"fmt\"\n\tthrift \"github.com/apache/thrift/lib/go/thrift\"\n\t\"time\"\n)\n\n// (needed to ensure safety because of naive import list construction.)\nvar _ = thrift.ZERO\nvar _ = fmt.Printf\nvar _ = context.Background\nvar _ = time.Now\nvar _ = bytes.Equal\n\nfunc init() {\n}\n"
  },
  {
    "path": "gen/osquery/osquery.go",
    "content": "// Code generated by Thrift Compiler (0.16.0). DO NOT EDIT.\n\npackage osquery\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"database/sql/driver\"\n\t\"errors\"\n\t\"fmt\"\n\tthrift \"github.com/apache/thrift/lib/go/thrift\"\n\t\"time\"\n)\n\n// (needed to ensure safety because of naive import list construction.)\nvar _ = thrift.ZERO\nvar _ = fmt.Printf\nvar _ = context.Background\nvar _ = time.Now\nvar _ = bytes.Equal\n\ntype ExtensionCode int64\n\nconst (\n\tExtensionCode_EXT_SUCCESS ExtensionCode = 0\n\tExtensionCode_EXT_FAILED  ExtensionCode = 1\n\tExtensionCode_EXT_FATAL   ExtensionCode = 2\n)\n\nfunc (p ExtensionCode) String() string {\n\tswitch p {\n\tcase ExtensionCode_EXT_SUCCESS:\n\t\treturn \"EXT_SUCCESS\"\n\tcase ExtensionCode_EXT_FAILED:\n\t\treturn \"EXT_FAILED\"\n\tcase ExtensionCode_EXT_FATAL:\n\t\treturn \"EXT_FATAL\"\n\t}\n\treturn \"<UNSET>\"\n}\n\nfunc ExtensionCodeFromString(s string) (ExtensionCode, error) {\n\tswitch s {\n\tcase \"EXT_SUCCESS\":\n\t\treturn ExtensionCode_EXT_SUCCESS, nil\n\tcase \"EXT_FAILED\":\n\t\treturn ExtensionCode_EXT_FAILED, nil\n\tcase \"EXT_FATAL\":\n\t\treturn ExtensionCode_EXT_FATAL, nil\n\t}\n\treturn ExtensionCode(0), fmt.Errorf(\"not a valid ExtensionCode string\")\n}\n\nfunc ExtensionCodePtr(v ExtensionCode) *ExtensionCode { return &v }\n\nfunc (p ExtensionCode) MarshalText() ([]byte, error) {\n\treturn []byte(p.String()), nil\n}\n\nfunc (p *ExtensionCode) UnmarshalText(text []byte) error {\n\tq, err := ExtensionCodeFromString(string(text))\n\tif err != nil {\n\t\treturn err\n\t}\n\t*p = q\n\treturn nil\n}\n\nfunc (p *ExtensionCode) Scan(value interface{}) error {\n\tv, ok := value.(int64)\n\tif !ok {\n\t\treturn errors.New(\"Scan value is not int64\")\n\t}\n\t*p = ExtensionCode(v)\n\treturn nil\n}\n\nfunc (p *ExtensionCode) Value() (driver.Value, error) {\n\tif p == nil {\n\t\treturn nil, nil\n\t}\n\treturn int64(*p), nil\n}\n\ntype ExtensionPluginRequest map[string]string\n\nfunc ExtensionPluginRequestPtr(v ExtensionPluginRequest) *ExtensionPluginRequest { return &v }\n\ntype ExtensionPluginResponse []map[string]string\n\nfunc ExtensionPluginResponsePtr(v ExtensionPluginResponse) *ExtensionPluginResponse { return &v }\n\ntype InternalOptionList map[string]*InternalOptionInfo\n\nfunc InternalOptionListPtr(v InternalOptionList) *InternalOptionList { return &v }\n\ntype ExtensionRouteUUID int64\n\nfunc ExtensionRouteUUIDPtr(v ExtensionRouteUUID) *ExtensionRouteUUID { return &v }\n\ntype ExtensionRouteTable map[string]ExtensionPluginResponse\n\nfunc ExtensionRouteTablePtr(v ExtensionRouteTable) *ExtensionRouteTable { return &v }\n\ntype ExtensionRegistry map[string]ExtensionRouteTable\n\nfunc ExtensionRegistryPtr(v ExtensionRegistry) *ExtensionRegistry { return &v }\n\ntype InternalExtensionList map[ExtensionRouteUUID]*InternalExtensionInfo\n\nfunc InternalExtensionListPtr(v InternalExtensionList) *InternalExtensionList { return &v }\n\n// Attributes:\n//  - Value\n//  - DefaultValue\n//  - Type\ntype InternalOptionInfo struct {\n\tValue        string `thrift:\"value,1\" db:\"value\" json:\"value\"`\n\tDefaultValue string `thrift:\"default_value,2\" db:\"default_value\" json:\"default_value\"`\n\tType         string `thrift:\"type,3\" db:\"type\" json:\"type\"`\n}\n\nfunc NewInternalOptionInfo() *InternalOptionInfo {\n\treturn &InternalOptionInfo{}\n}\n\nfunc (p *InternalOptionInfo) GetValue() string {\n\treturn p.Value\n}\n\nfunc (p *InternalOptionInfo) GetDefaultValue() string {\n\treturn p.DefaultValue\n}\n\nfunc (p *InternalOptionInfo) GetType() string {\n\treturn p.Type\n}\nfunc (p *InternalOptionInfo) Read(ctx context.Context, iprot thrift.TProtocol) error {\n\tif _, err := iprot.ReadStructBegin(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T read error: \", p), err)\n\t}\n\n\tfor {\n\t\t_, fieldTypeId, fieldId, err := iprot.ReadFieldBegin(ctx)\n\t\tif err != nil {\n\t\t\treturn thrift.PrependError(fmt.Sprintf(\"%T field %d read error: \", p, fieldId), err)\n\t\t}\n\t\tif fieldTypeId == thrift.STOP {\n\t\t\tbreak\n\t\t}\n\t\tswitch fieldId {\n\t\tcase 1:\n\t\t\tif fieldTypeId == thrift.STRING {\n\t\t\t\tif err := p.ReadField1(ctx, iprot); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := iprot.Skip(ctx, fieldTypeId); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif fieldTypeId == thrift.STRING {\n\t\t\t\tif err := p.ReadField2(ctx, iprot); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := iprot.Skip(ctx, fieldTypeId); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\tcase 3:\n\t\t\tif fieldTypeId == thrift.STRING {\n\t\t\t\tif err := p.ReadField3(ctx, iprot); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := iprot.Skip(ctx, fieldTypeId); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tif err := iprot.Skip(ctx, fieldTypeId); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\tif err := iprot.ReadFieldEnd(ctx); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif err := iprot.ReadStructEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T read struct end error: \", p), err)\n\t}\n\treturn nil\n}\n\nfunc (p *InternalOptionInfo) ReadField1(ctx context.Context, iprot thrift.TProtocol) error {\n\tif v, err := iprot.ReadString(ctx); err != nil {\n\t\treturn thrift.PrependError(\"error reading field 1: \", err)\n\t} else {\n\t\tp.Value = v\n\t}\n\treturn nil\n}\n\nfunc (p *InternalOptionInfo) ReadField2(ctx context.Context, iprot thrift.TProtocol) error {\n\tif v, err := iprot.ReadString(ctx); err != nil {\n\t\treturn thrift.PrependError(\"error reading field 2: \", err)\n\t} else {\n\t\tp.DefaultValue = v\n\t}\n\treturn nil\n}\n\nfunc (p *InternalOptionInfo) ReadField3(ctx context.Context, iprot thrift.TProtocol) error {\n\tif v, err := iprot.ReadString(ctx); err != nil {\n\t\treturn thrift.PrependError(\"error reading field 3: \", err)\n\t} else {\n\t\tp.Type = v\n\t}\n\treturn nil\n}\n\nfunc (p *InternalOptionInfo) Write(ctx context.Context, oprot thrift.TProtocol) error {\n\tif err := oprot.WriteStructBegin(ctx, \"InternalOptionInfo\"); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write struct begin error: \", p), err)\n\t}\n\tif p != nil {\n\t\tif err := p.writeField1(ctx, oprot); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := p.writeField2(ctx, oprot); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := p.writeField3(ctx, oprot); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif err := oprot.WriteFieldStop(ctx); err != nil {\n\t\treturn thrift.PrependError(\"write field stop error: \", err)\n\t}\n\tif err := oprot.WriteStructEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(\"write struct stop error: \", err)\n\t}\n\treturn nil\n}\n\nfunc (p *InternalOptionInfo) writeField1(ctx context.Context, oprot thrift.TProtocol) (err error) {\n\tif err := oprot.WriteFieldBegin(ctx, \"value\", thrift.STRING, 1); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write field begin error 1:value: \", p), err)\n\t}\n\tif err := oprot.WriteString(ctx, string(p.Value)); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T.value (1) field write error: \", p), err)\n\t}\n\tif err := oprot.WriteFieldEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write field end error 1:value: \", p), err)\n\t}\n\treturn err\n}\n\nfunc (p *InternalOptionInfo) writeField2(ctx context.Context, oprot thrift.TProtocol) (err error) {\n\tif err := oprot.WriteFieldBegin(ctx, \"default_value\", thrift.STRING, 2); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write field begin error 2:default_value: \", p), err)\n\t}\n\tif err := oprot.WriteString(ctx, string(p.DefaultValue)); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T.default_value (2) field write error: \", p), err)\n\t}\n\tif err := oprot.WriteFieldEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write field end error 2:default_value: \", p), err)\n\t}\n\treturn err\n}\n\nfunc (p *InternalOptionInfo) writeField3(ctx context.Context, oprot thrift.TProtocol) (err error) {\n\tif err := oprot.WriteFieldBegin(ctx, \"type\", thrift.STRING, 3); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write field begin error 3:type: \", p), err)\n\t}\n\tif err := oprot.WriteString(ctx, string(p.Type)); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T.type (3) field write error: \", p), err)\n\t}\n\tif err := oprot.WriteFieldEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write field end error 3:type: \", p), err)\n\t}\n\treturn err\n}\n\nfunc (p *InternalOptionInfo) Equals(other *InternalOptionInfo) bool {\n\tif p == other {\n\t\treturn true\n\t} else if p == nil || other == nil {\n\t\treturn false\n\t}\n\tif p.Value != other.Value {\n\t\treturn false\n\t}\n\tif p.DefaultValue != other.DefaultValue {\n\t\treturn false\n\t}\n\tif p.Type != other.Type {\n\t\treturn false\n\t}\n\treturn true\n}\n\nfunc (p *InternalOptionInfo) String() string {\n\tif p == nil {\n\t\treturn \"<nil>\"\n\t}\n\treturn fmt.Sprintf(\"InternalOptionInfo(%+v)\", *p)\n}\n\n// Attributes:\n//  - Name\n//  - Version\n//  - SdkVersion\n//  - MinSdkVersion\ntype InternalExtensionInfo struct {\n\tName          string `thrift:\"name,1\" db:\"name\" json:\"name\"`\n\tVersion       string `thrift:\"version,2\" db:\"version\" json:\"version\"`\n\tSdkVersion    string `thrift:\"sdk_version,3\" db:\"sdk_version\" json:\"sdk_version\"`\n\tMinSdkVersion string `thrift:\"min_sdk_version,4\" db:\"min_sdk_version\" json:\"min_sdk_version\"`\n}\n\nfunc NewInternalExtensionInfo() *InternalExtensionInfo {\n\treturn &InternalExtensionInfo{}\n}\n\nfunc (p *InternalExtensionInfo) GetName() string {\n\treturn p.Name\n}\n\nfunc (p *InternalExtensionInfo) GetVersion() string {\n\treturn p.Version\n}\n\nfunc (p *InternalExtensionInfo) GetSdkVersion() string {\n\treturn p.SdkVersion\n}\n\nfunc (p *InternalExtensionInfo) GetMinSdkVersion() string {\n\treturn p.MinSdkVersion\n}\nfunc (p *InternalExtensionInfo) Read(ctx context.Context, iprot thrift.TProtocol) error {\n\tif _, err := iprot.ReadStructBegin(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T read error: \", p), err)\n\t}\n\n\tfor {\n\t\t_, fieldTypeId, fieldId, err := iprot.ReadFieldBegin(ctx)\n\t\tif err != nil {\n\t\t\treturn thrift.PrependError(fmt.Sprintf(\"%T field %d read error: \", p, fieldId), err)\n\t\t}\n\t\tif fieldTypeId == thrift.STOP {\n\t\t\tbreak\n\t\t}\n\t\tswitch fieldId {\n\t\tcase 1:\n\t\t\tif fieldTypeId == thrift.STRING {\n\t\t\t\tif err := p.ReadField1(ctx, iprot); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := iprot.Skip(ctx, fieldTypeId); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif fieldTypeId == thrift.STRING {\n\t\t\t\tif err := p.ReadField2(ctx, iprot); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := iprot.Skip(ctx, fieldTypeId); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\tcase 3:\n\t\t\tif fieldTypeId == thrift.STRING {\n\t\t\t\tif err := p.ReadField3(ctx, iprot); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := iprot.Skip(ctx, fieldTypeId); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\tcase 4:\n\t\t\tif fieldTypeId == thrift.STRING {\n\t\t\t\tif err := p.ReadField4(ctx, iprot); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := iprot.Skip(ctx, fieldTypeId); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tif err := iprot.Skip(ctx, fieldTypeId); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\tif err := iprot.ReadFieldEnd(ctx); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif err := iprot.ReadStructEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T read struct end error: \", p), err)\n\t}\n\treturn nil\n}\n\nfunc (p *InternalExtensionInfo) ReadField1(ctx context.Context, iprot thrift.TProtocol) error {\n\tif v, err := iprot.ReadString(ctx); err != nil {\n\t\treturn thrift.PrependError(\"error reading field 1: \", err)\n\t} else {\n\t\tp.Name = v\n\t}\n\treturn nil\n}\n\nfunc (p *InternalExtensionInfo) ReadField2(ctx context.Context, iprot thrift.TProtocol) error {\n\tif v, err := iprot.ReadString(ctx); err != nil {\n\t\treturn thrift.PrependError(\"error reading field 2: \", err)\n\t} else {\n\t\tp.Version = v\n\t}\n\treturn nil\n}\n\nfunc (p *InternalExtensionInfo) ReadField3(ctx context.Context, iprot thrift.TProtocol) error {\n\tif v, err := iprot.ReadString(ctx); err != nil {\n\t\treturn thrift.PrependError(\"error reading field 3: \", err)\n\t} else {\n\t\tp.SdkVersion = v\n\t}\n\treturn nil\n}\n\nfunc (p *InternalExtensionInfo) ReadField4(ctx context.Context, iprot thrift.TProtocol) error {\n\tif v, err := iprot.ReadString(ctx); err != nil {\n\t\treturn thrift.PrependError(\"error reading field 4: \", err)\n\t} else {\n\t\tp.MinSdkVersion = v\n\t}\n\treturn nil\n}\n\nfunc (p *InternalExtensionInfo) Write(ctx context.Context, oprot thrift.TProtocol) error {\n\tif err := oprot.WriteStructBegin(ctx, \"InternalExtensionInfo\"); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write struct begin error: \", p), err)\n\t}\n\tif p != nil {\n\t\tif err := p.writeField1(ctx, oprot); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := p.writeField2(ctx, oprot); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := p.writeField3(ctx, oprot); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := p.writeField4(ctx, oprot); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif err := oprot.WriteFieldStop(ctx); err != nil {\n\t\treturn thrift.PrependError(\"write field stop error: \", err)\n\t}\n\tif err := oprot.WriteStructEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(\"write struct stop error: \", err)\n\t}\n\treturn nil\n}\n\nfunc (p *InternalExtensionInfo) writeField1(ctx context.Context, oprot thrift.TProtocol) (err error) {\n\tif err := oprot.WriteFieldBegin(ctx, \"name\", thrift.STRING, 1); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write field begin error 1:name: \", p), err)\n\t}\n\tif err := oprot.WriteString(ctx, string(p.Name)); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T.name (1) field write error: \", p), err)\n\t}\n\tif err := oprot.WriteFieldEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write field end error 1:name: \", p), err)\n\t}\n\treturn err\n}\n\nfunc (p *InternalExtensionInfo) writeField2(ctx context.Context, oprot thrift.TProtocol) (err error) {\n\tif err := oprot.WriteFieldBegin(ctx, \"version\", thrift.STRING, 2); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write field begin error 2:version: \", p), err)\n\t}\n\tif err := oprot.WriteString(ctx, string(p.Version)); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T.version (2) field write error: \", p), err)\n\t}\n\tif err := oprot.WriteFieldEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write field end error 2:version: \", p), err)\n\t}\n\treturn err\n}\n\nfunc (p *InternalExtensionInfo) writeField3(ctx context.Context, oprot thrift.TProtocol) (err error) {\n\tif err := oprot.WriteFieldBegin(ctx, \"sdk_version\", thrift.STRING, 3); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write field begin error 3:sdk_version: \", p), err)\n\t}\n\tif err := oprot.WriteString(ctx, string(p.SdkVersion)); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T.sdk_version (3) field write error: \", p), err)\n\t}\n\tif err := oprot.WriteFieldEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write field end error 3:sdk_version: \", p), err)\n\t}\n\treturn err\n}\n\nfunc (p *InternalExtensionInfo) writeField4(ctx context.Context, oprot thrift.TProtocol) (err error) {\n\tif err := oprot.WriteFieldBegin(ctx, \"min_sdk_version\", thrift.STRING, 4); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write field begin error 4:min_sdk_version: \", p), err)\n\t}\n\tif err := oprot.WriteString(ctx, string(p.MinSdkVersion)); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T.min_sdk_version (4) field write error: \", p), err)\n\t}\n\tif err := oprot.WriteFieldEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write field end error 4:min_sdk_version: \", p), err)\n\t}\n\treturn err\n}\n\nfunc (p *InternalExtensionInfo) Equals(other *InternalExtensionInfo) bool {\n\tif p == other {\n\t\treturn true\n\t} else if p == nil || other == nil {\n\t\treturn false\n\t}\n\tif p.Name != other.Name {\n\t\treturn false\n\t}\n\tif p.Version != other.Version {\n\t\treturn false\n\t}\n\tif p.SdkVersion != other.SdkVersion {\n\t\treturn false\n\t}\n\tif p.MinSdkVersion != other.MinSdkVersion {\n\t\treturn false\n\t}\n\treturn true\n}\n\nfunc (p *InternalExtensionInfo) String() string {\n\tif p == nil {\n\t\treturn \"<nil>\"\n\t}\n\treturn fmt.Sprintf(\"InternalExtensionInfo(%+v)\", *p)\n}\n\n// Attributes:\n//  - Code\n//  - Message\n//  - UUID\ntype ExtensionStatus struct {\n\tCode    int32              `thrift:\"code,1\" db:\"code\" json:\"code\"`\n\tMessage string             `thrift:\"message,2\" db:\"message\" json:\"message\"`\n\tUUID    ExtensionRouteUUID `thrift:\"uuid,3\" db:\"uuid\" json:\"uuid\"`\n}\n\nfunc NewExtensionStatus() *ExtensionStatus {\n\treturn &ExtensionStatus{}\n}\n\nfunc (p *ExtensionStatus) GetCode() int32 {\n\treturn p.Code\n}\n\nfunc (p *ExtensionStatus) GetMessage() string {\n\treturn p.Message\n}\n\nfunc (p *ExtensionStatus) GetUUID() ExtensionRouteUUID {\n\treturn p.UUID\n}\nfunc (p *ExtensionStatus) Read(ctx context.Context, iprot thrift.TProtocol) error {\n\tif _, err := iprot.ReadStructBegin(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T read error: \", p), err)\n\t}\n\n\tfor {\n\t\t_, fieldTypeId, fieldId, err := iprot.ReadFieldBegin(ctx)\n\t\tif err != nil {\n\t\t\treturn thrift.PrependError(fmt.Sprintf(\"%T field %d read error: \", p, fieldId), err)\n\t\t}\n\t\tif fieldTypeId == thrift.STOP {\n\t\t\tbreak\n\t\t}\n\t\tswitch fieldId {\n\t\tcase 1:\n\t\t\tif fieldTypeId == thrift.I32 {\n\t\t\t\tif err := p.ReadField1(ctx, iprot); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := iprot.Skip(ctx, fieldTypeId); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif fieldTypeId == thrift.STRING {\n\t\t\t\tif err := p.ReadField2(ctx, iprot); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := iprot.Skip(ctx, fieldTypeId); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\tcase 3:\n\t\t\tif fieldTypeId == thrift.I64 {\n\t\t\t\tif err := p.ReadField3(ctx, iprot); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := iprot.Skip(ctx, fieldTypeId); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tif err := iprot.Skip(ctx, fieldTypeId); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\tif err := iprot.ReadFieldEnd(ctx); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif err := iprot.ReadStructEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T read struct end error: \", p), err)\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionStatus) ReadField1(ctx context.Context, iprot thrift.TProtocol) error {\n\tif v, err := iprot.ReadI32(ctx); err != nil {\n\t\treturn thrift.PrependError(\"error reading field 1: \", err)\n\t} else {\n\t\tp.Code = v\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionStatus) ReadField2(ctx context.Context, iprot thrift.TProtocol) error {\n\tif v, err := iprot.ReadString(ctx); err != nil {\n\t\treturn thrift.PrependError(\"error reading field 2: \", err)\n\t} else {\n\t\tp.Message = v\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionStatus) ReadField3(ctx context.Context, iprot thrift.TProtocol) error {\n\tif v, err := iprot.ReadI64(ctx); err != nil {\n\t\treturn thrift.PrependError(\"error reading field 3: \", err)\n\t} else {\n\t\ttemp := ExtensionRouteUUID(v)\n\t\tp.UUID = temp\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionStatus) Write(ctx context.Context, oprot thrift.TProtocol) error {\n\tif err := oprot.WriteStructBegin(ctx, \"ExtensionStatus\"); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write struct begin error: \", p), err)\n\t}\n\tif p != nil {\n\t\tif err := p.writeField1(ctx, oprot); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := p.writeField2(ctx, oprot); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := p.writeField3(ctx, oprot); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif err := oprot.WriteFieldStop(ctx); err != nil {\n\t\treturn thrift.PrependError(\"write field stop error: \", err)\n\t}\n\tif err := oprot.WriteStructEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(\"write struct stop error: \", err)\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionStatus) writeField1(ctx context.Context, oprot thrift.TProtocol) (err error) {\n\tif err := oprot.WriteFieldBegin(ctx, \"code\", thrift.I32, 1); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write field begin error 1:code: \", p), err)\n\t}\n\tif err := oprot.WriteI32(ctx, int32(p.Code)); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T.code (1) field write error: \", p), err)\n\t}\n\tif err := oprot.WriteFieldEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write field end error 1:code: \", p), err)\n\t}\n\treturn err\n}\n\nfunc (p *ExtensionStatus) writeField2(ctx context.Context, oprot thrift.TProtocol) (err error) {\n\tif err := oprot.WriteFieldBegin(ctx, \"message\", thrift.STRING, 2); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write field begin error 2:message: \", p), err)\n\t}\n\tif err := oprot.WriteString(ctx, string(p.Message)); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T.message (2) field write error: \", p), err)\n\t}\n\tif err := oprot.WriteFieldEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write field end error 2:message: \", p), err)\n\t}\n\treturn err\n}\n\nfunc (p *ExtensionStatus) writeField3(ctx context.Context, oprot thrift.TProtocol) (err error) {\n\tif err := oprot.WriteFieldBegin(ctx, \"uuid\", thrift.I64, 3); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write field begin error 3:uuid: \", p), err)\n\t}\n\tif err := oprot.WriteI64(ctx, int64(p.UUID)); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T.uuid (3) field write error: \", p), err)\n\t}\n\tif err := oprot.WriteFieldEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write field end error 3:uuid: \", p), err)\n\t}\n\treturn err\n}\n\nfunc (p *ExtensionStatus) Equals(other *ExtensionStatus) bool {\n\tif p == other {\n\t\treturn true\n\t} else if p == nil || other == nil {\n\t\treturn false\n\t}\n\tif p.Code != other.Code {\n\t\treturn false\n\t}\n\tif p.Message != other.Message {\n\t\treturn false\n\t}\n\tif p.UUID != other.UUID {\n\t\treturn false\n\t}\n\treturn true\n}\n\nfunc (p *ExtensionStatus) String() string {\n\tif p == nil {\n\t\treturn \"<nil>\"\n\t}\n\treturn fmt.Sprintf(\"ExtensionStatus(%+v)\", *p)\n}\n\n// Attributes:\n//  - Status\n//  - Response\ntype ExtensionResponse struct {\n\tStatus   *ExtensionStatus        `thrift:\"status,1\" db:\"status\" json:\"status\"`\n\tResponse ExtensionPluginResponse `thrift:\"response,2\" db:\"response\" json:\"response\"`\n}\n\nfunc NewExtensionResponse() *ExtensionResponse {\n\treturn &ExtensionResponse{}\n}\n\nvar ExtensionResponse_Status_DEFAULT *ExtensionStatus\n\nfunc (p *ExtensionResponse) GetStatus() *ExtensionStatus {\n\tif !p.IsSetStatus() {\n\t\treturn ExtensionResponse_Status_DEFAULT\n\t}\n\treturn p.Status\n}\n\nfunc (p *ExtensionResponse) GetResponse() ExtensionPluginResponse {\n\treturn p.Response\n}\nfunc (p *ExtensionResponse) IsSetStatus() bool {\n\treturn p.Status != nil\n}\n\nfunc (p *ExtensionResponse) Read(ctx context.Context, iprot thrift.TProtocol) error {\n\tif _, err := iprot.ReadStructBegin(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T read error: \", p), err)\n\t}\n\n\tfor {\n\t\t_, fieldTypeId, fieldId, err := iprot.ReadFieldBegin(ctx)\n\t\tif err != nil {\n\t\t\treturn thrift.PrependError(fmt.Sprintf(\"%T field %d read error: \", p, fieldId), err)\n\t\t}\n\t\tif fieldTypeId == thrift.STOP {\n\t\t\tbreak\n\t\t}\n\t\tswitch fieldId {\n\t\tcase 1:\n\t\t\tif fieldTypeId == thrift.STRUCT {\n\t\t\t\tif err := p.ReadField1(ctx, iprot); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := iprot.Skip(ctx, fieldTypeId); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif fieldTypeId == thrift.LIST {\n\t\t\t\tif err := p.ReadField2(ctx, iprot); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := iprot.Skip(ctx, fieldTypeId); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tif err := iprot.Skip(ctx, fieldTypeId); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\tif err := iprot.ReadFieldEnd(ctx); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif err := iprot.ReadStructEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T read struct end error: \", p), err)\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionResponse) ReadField1(ctx context.Context, iprot thrift.TProtocol) error {\n\tp.Status = &ExtensionStatus{}\n\tif err := p.Status.Read(ctx, iprot); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T error reading struct: \", p.Status), err)\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionResponse) ReadField2(ctx context.Context, iprot thrift.TProtocol) error {\n\t_, size, err := iprot.ReadListBegin(ctx)\n\tif err != nil {\n\t\treturn thrift.PrependError(\"error reading list begin: \", err)\n\t}\n\ttSlice := make(ExtensionPluginResponse, 0, size)\n\tp.Response = tSlice\n\tfor i := 0; i < size; i++ {\n\t\t_, _, size, err := iprot.ReadMapBegin(ctx)\n\t\tif err != nil {\n\t\t\treturn thrift.PrependError(\"error reading map begin: \", err)\n\t\t}\n\t\ttMap := make(map[string]string, size)\n\t\t_elem0 := tMap\n\t\tfor i := 0; i < size; i++ {\n\t\t\tvar _key1 string\n\t\t\tif v, err := iprot.ReadString(ctx); err != nil {\n\t\t\t\treturn thrift.PrependError(\"error reading field 0: \", err)\n\t\t\t} else {\n\t\t\t\t_key1 = v\n\t\t\t}\n\t\t\tvar _val2 string\n\t\t\tif v, err := iprot.ReadString(ctx); err != nil {\n\t\t\t\treturn thrift.PrependError(\"error reading field 0: \", err)\n\t\t\t} else {\n\t\t\t\t_val2 = v\n\t\t\t}\n\t\t\t_elem0[_key1] = _val2\n\t\t}\n\t\tif err := iprot.ReadMapEnd(ctx); err != nil {\n\t\t\treturn thrift.PrependError(\"error reading map end: \", err)\n\t\t}\n\t\tp.Response = append(p.Response, _elem0)\n\t}\n\tif err := iprot.ReadListEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(\"error reading list end: \", err)\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionResponse) Write(ctx context.Context, oprot thrift.TProtocol) error {\n\tif err := oprot.WriteStructBegin(ctx, \"ExtensionResponse\"); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write struct begin error: \", p), err)\n\t}\n\tif p != nil {\n\t\tif err := p.writeField1(ctx, oprot); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := p.writeField2(ctx, oprot); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif err := oprot.WriteFieldStop(ctx); err != nil {\n\t\treturn thrift.PrependError(\"write field stop error: \", err)\n\t}\n\tif err := oprot.WriteStructEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(\"write struct stop error: \", err)\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionResponse) writeField1(ctx context.Context, oprot thrift.TProtocol) (err error) {\n\tif err := oprot.WriteFieldBegin(ctx, \"status\", thrift.STRUCT, 1); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write field begin error 1:status: \", p), err)\n\t}\n\tif err := p.Status.Write(ctx, oprot); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T error writing struct: \", p.Status), err)\n\t}\n\tif err := oprot.WriteFieldEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write field end error 1:status: \", p), err)\n\t}\n\treturn err\n}\n\nfunc (p *ExtensionResponse) writeField2(ctx context.Context, oprot thrift.TProtocol) (err error) {\n\tif err := oprot.WriteFieldBegin(ctx, \"response\", thrift.LIST, 2); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write field begin error 2:response: \", p), err)\n\t}\n\tif err := oprot.WriteListBegin(ctx, thrift.MAP, len(p.Response)); err != nil {\n\t\treturn thrift.PrependError(\"error writing list begin: \", err)\n\t}\n\tfor _, v := range p.Response {\n\t\tif err := oprot.WriteMapBegin(ctx, thrift.STRING, thrift.STRING, len(v)); err != nil {\n\t\t\treturn thrift.PrependError(\"error writing map begin: \", err)\n\t\t}\n\t\tfor k, v := range v {\n\t\t\tif err := oprot.WriteString(ctx, string(k)); err != nil {\n\t\t\t\treturn thrift.PrependError(fmt.Sprintf(\"%T. (0) field write error: \", p), err)\n\t\t\t}\n\t\t\tif err := oprot.WriteString(ctx, string(v)); err != nil {\n\t\t\t\treturn thrift.PrependError(fmt.Sprintf(\"%T. (0) field write error: \", p), err)\n\t\t\t}\n\t\t}\n\t\tif err := oprot.WriteMapEnd(ctx); err != nil {\n\t\t\treturn thrift.PrependError(\"error writing map end: \", err)\n\t\t}\n\t}\n\tif err := oprot.WriteListEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(\"error writing list end: \", err)\n\t}\n\tif err := oprot.WriteFieldEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write field end error 2:response: \", p), err)\n\t}\n\treturn err\n}\n\nfunc (p *ExtensionResponse) Equals(other *ExtensionResponse) bool {\n\tif p == other {\n\t\treturn true\n\t} else if p == nil || other == nil {\n\t\treturn false\n\t}\n\tif !p.Status.Equals(other.Status) {\n\t\treturn false\n\t}\n\tif len(p.Response) != len(other.Response) {\n\t\treturn false\n\t}\n\tfor i, _tgt := range p.Response {\n\t\t_src3 := other.Response[i]\n\t\tif len(_tgt) != len(_src3) {\n\t\t\treturn false\n\t\t}\n\t\tfor k, _tgt := range _tgt {\n\t\t\t_src4 := _src3[k]\n\t\t\tif _tgt != _src4 {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t}\n\treturn true\n}\n\nfunc (p *ExtensionResponse) String() string {\n\tif p == nil {\n\t\treturn \"<nil>\"\n\t}\n\treturn fmt.Sprintf(\"ExtensionResponse(%+v)\", *p)\n}\n\n// Attributes:\n//  - Code\n//  - Message\n//  - UUID\ntype ExtensionException struct {\n\tCode    int32              `thrift:\"code,1\" db:\"code\" json:\"code\"`\n\tMessage string             `thrift:\"message,2\" db:\"message\" json:\"message\"`\n\tUUID    ExtensionRouteUUID `thrift:\"uuid,3\" db:\"uuid\" json:\"uuid\"`\n}\n\nfunc NewExtensionException() *ExtensionException {\n\treturn &ExtensionException{}\n}\n\nfunc (p *ExtensionException) GetCode() int32 {\n\treturn p.Code\n}\n\nfunc (p *ExtensionException) GetMessage() string {\n\treturn p.Message\n}\n\nfunc (p *ExtensionException) GetUUID() ExtensionRouteUUID {\n\treturn p.UUID\n}\nfunc (p *ExtensionException) Read(ctx context.Context, iprot thrift.TProtocol) error {\n\tif _, err := iprot.ReadStructBegin(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T read error: \", p), err)\n\t}\n\n\tfor {\n\t\t_, fieldTypeId, fieldId, err := iprot.ReadFieldBegin(ctx)\n\t\tif err != nil {\n\t\t\treturn thrift.PrependError(fmt.Sprintf(\"%T field %d read error: \", p, fieldId), err)\n\t\t}\n\t\tif fieldTypeId == thrift.STOP {\n\t\t\tbreak\n\t\t}\n\t\tswitch fieldId {\n\t\tcase 1:\n\t\t\tif fieldTypeId == thrift.I32 {\n\t\t\t\tif err := p.ReadField1(ctx, iprot); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := iprot.Skip(ctx, fieldTypeId); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif fieldTypeId == thrift.STRING {\n\t\t\t\tif err := p.ReadField2(ctx, iprot); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := iprot.Skip(ctx, fieldTypeId); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\tcase 3:\n\t\t\tif fieldTypeId == thrift.I64 {\n\t\t\t\tif err := p.ReadField3(ctx, iprot); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := iprot.Skip(ctx, fieldTypeId); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tif err := iprot.Skip(ctx, fieldTypeId); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\tif err := iprot.ReadFieldEnd(ctx); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif err := iprot.ReadStructEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T read struct end error: \", p), err)\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionException) ReadField1(ctx context.Context, iprot thrift.TProtocol) error {\n\tif v, err := iprot.ReadI32(ctx); err != nil {\n\t\treturn thrift.PrependError(\"error reading field 1: \", err)\n\t} else {\n\t\tp.Code = v\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionException) ReadField2(ctx context.Context, iprot thrift.TProtocol) error {\n\tif v, err := iprot.ReadString(ctx); err != nil {\n\t\treturn thrift.PrependError(\"error reading field 2: \", err)\n\t} else {\n\t\tp.Message = v\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionException) ReadField3(ctx context.Context, iprot thrift.TProtocol) error {\n\tif v, err := iprot.ReadI64(ctx); err != nil {\n\t\treturn thrift.PrependError(\"error reading field 3: \", err)\n\t} else {\n\t\ttemp := ExtensionRouteUUID(v)\n\t\tp.UUID = temp\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionException) Write(ctx context.Context, oprot thrift.TProtocol) error {\n\tif err := oprot.WriteStructBegin(ctx, \"ExtensionException\"); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write struct begin error: \", p), err)\n\t}\n\tif p != nil {\n\t\tif err := p.writeField1(ctx, oprot); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := p.writeField2(ctx, oprot); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := p.writeField3(ctx, oprot); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif err := oprot.WriteFieldStop(ctx); err != nil {\n\t\treturn thrift.PrependError(\"write field stop error: \", err)\n\t}\n\tif err := oprot.WriteStructEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(\"write struct stop error: \", err)\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionException) writeField1(ctx context.Context, oprot thrift.TProtocol) (err error) {\n\tif err := oprot.WriteFieldBegin(ctx, \"code\", thrift.I32, 1); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write field begin error 1:code: \", p), err)\n\t}\n\tif err := oprot.WriteI32(ctx, int32(p.Code)); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T.code (1) field write error: \", p), err)\n\t}\n\tif err := oprot.WriteFieldEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write field end error 1:code: \", p), err)\n\t}\n\treturn err\n}\n\nfunc (p *ExtensionException) writeField2(ctx context.Context, oprot thrift.TProtocol) (err error) {\n\tif err := oprot.WriteFieldBegin(ctx, \"message\", thrift.STRING, 2); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write field begin error 2:message: \", p), err)\n\t}\n\tif err := oprot.WriteString(ctx, string(p.Message)); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T.message (2) field write error: \", p), err)\n\t}\n\tif err := oprot.WriteFieldEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write field end error 2:message: \", p), err)\n\t}\n\treturn err\n}\n\nfunc (p *ExtensionException) writeField3(ctx context.Context, oprot thrift.TProtocol) (err error) {\n\tif err := oprot.WriteFieldBegin(ctx, \"uuid\", thrift.I64, 3); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write field begin error 3:uuid: \", p), err)\n\t}\n\tif err := oprot.WriteI64(ctx, int64(p.UUID)); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T.uuid (3) field write error: \", p), err)\n\t}\n\tif err := oprot.WriteFieldEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write field end error 3:uuid: \", p), err)\n\t}\n\treturn err\n}\n\nfunc (p *ExtensionException) Equals(other *ExtensionException) bool {\n\tif p == other {\n\t\treturn true\n\t} else if p == nil || other == nil {\n\t\treturn false\n\t}\n\tif p.Code != other.Code {\n\t\treturn false\n\t}\n\tif p.Message != other.Message {\n\t\treturn false\n\t}\n\tif p.UUID != other.UUID {\n\t\treturn false\n\t}\n\treturn true\n}\n\nfunc (p *ExtensionException) String() string {\n\tif p == nil {\n\t\treturn \"<nil>\"\n\t}\n\treturn fmt.Sprintf(\"ExtensionException(%+v)\", *p)\n}\n\nfunc (p *ExtensionException) Error() string {\n\treturn p.String()\n}\n\nfunc (ExtensionException) TExceptionType() thrift.TExceptionType {\n\treturn thrift.TExceptionTypeCompiled\n}\n\nvar _ thrift.TException = (*ExtensionException)(nil)\n\ntype Extension interface {\n\tPing(ctx context.Context) (_r *ExtensionStatus, _err error)\n\t// Parameters:\n\t//  - Registry\n\t//  - Item\n\t//  - Request\n\tCall(ctx context.Context, registry string, item string, request ExtensionPluginRequest) (_r *ExtensionResponse, _err error)\n\tShutdown(ctx context.Context) (_err error)\n}\n\ntype ExtensionClient struct {\n\tc    thrift.TClient\n\tmeta thrift.ResponseMeta\n}\n\nfunc NewExtensionClientFactory(t thrift.TTransport, f thrift.TProtocolFactory) *ExtensionClient {\n\treturn &ExtensionClient{\n\t\tc: thrift.NewTStandardClient(f.GetProtocol(t), f.GetProtocol(t)),\n\t}\n}\n\nfunc NewExtensionClientProtocol(t thrift.TTransport, iprot thrift.TProtocol, oprot thrift.TProtocol) *ExtensionClient {\n\treturn &ExtensionClient{\n\t\tc: thrift.NewTStandardClient(iprot, oprot),\n\t}\n}\n\nfunc NewExtensionClient(c thrift.TClient) *ExtensionClient {\n\treturn &ExtensionClient{\n\t\tc: c,\n\t}\n}\n\nfunc (p *ExtensionClient) Client_() thrift.TClient {\n\treturn p.c\n}\n\nfunc (p *ExtensionClient) LastResponseMeta_() thrift.ResponseMeta {\n\treturn p.meta\n}\n\nfunc (p *ExtensionClient) SetLastResponseMeta_(meta thrift.ResponseMeta) {\n\tp.meta = meta\n}\n\nfunc (p *ExtensionClient) Ping(ctx context.Context) (_r *ExtensionStatus, _err error) {\n\tvar _args5 ExtensionPingArgs\n\tvar _result7 ExtensionPingResult\n\tvar _meta6 thrift.ResponseMeta\n\t_meta6, _err = p.Client_().Call(ctx, \"ping\", &_args5, &_result7)\n\tp.SetLastResponseMeta_(_meta6)\n\tif _err != nil {\n\t\treturn\n\t}\n\tif _ret8 := _result7.GetSuccess(); _ret8 != nil {\n\t\treturn _ret8, nil\n\t}\n\treturn nil, thrift.NewTApplicationException(thrift.MISSING_RESULT, \"ping failed: unknown result\")\n}\n\n// Parameters:\n//  - Registry\n//  - Item\n//  - Request\nfunc (p *ExtensionClient) Call(ctx context.Context, registry string, item string, request ExtensionPluginRequest) (_r *ExtensionResponse, _err error) {\n\tvar _args9 ExtensionCallArgs\n\t_args9.Registry = registry\n\t_args9.Item = item\n\t_args9.Request = request\n\tvar _result11 ExtensionCallResult\n\tvar _meta10 thrift.ResponseMeta\n\t_meta10, _err = p.Client_().Call(ctx, \"call\", &_args9, &_result11)\n\tp.SetLastResponseMeta_(_meta10)\n\tif _err != nil {\n\t\treturn\n\t}\n\tif _ret12 := _result11.GetSuccess(); _ret12 != nil {\n\t\treturn _ret12, nil\n\t}\n\treturn nil, thrift.NewTApplicationException(thrift.MISSING_RESULT, \"call failed: unknown result\")\n}\n\nfunc (p *ExtensionClient) Shutdown(ctx context.Context) (_err error) {\n\tvar _args13 ExtensionShutdownArgs\n\tvar _result15 ExtensionShutdownResult\n\tvar _meta14 thrift.ResponseMeta\n\t_meta14, _err = p.Client_().Call(ctx, \"shutdown\", &_args13, &_result15)\n\tp.SetLastResponseMeta_(_meta14)\n\tif _err != nil {\n\t\treturn\n\t}\n\treturn nil\n}\n\ntype ExtensionProcessor struct {\n\tprocessorMap map[string]thrift.TProcessorFunction\n\thandler      Extension\n}\n\nfunc (p *ExtensionProcessor) AddToProcessorMap(key string, processor thrift.TProcessorFunction) {\n\tp.processorMap[key] = processor\n}\n\nfunc (p *ExtensionProcessor) GetProcessorFunction(key string) (processor thrift.TProcessorFunction, ok bool) {\n\tprocessor, ok = p.processorMap[key]\n\treturn processor, ok\n}\n\nfunc (p *ExtensionProcessor) ProcessorMap() map[string]thrift.TProcessorFunction {\n\treturn p.processorMap\n}\n\nfunc NewExtensionProcessor(handler Extension) *ExtensionProcessor {\n\n\tself16 := &ExtensionProcessor{handler: handler, processorMap: make(map[string]thrift.TProcessorFunction)}\n\tself16.processorMap[\"ping\"] = &extensionProcessorPing{handler: handler}\n\tself16.processorMap[\"call\"] = &extensionProcessorCall{handler: handler}\n\tself16.processorMap[\"shutdown\"] = &extensionProcessorShutdown{handler: handler}\n\treturn self16\n}\n\nfunc (p *ExtensionProcessor) Process(ctx context.Context, iprot, oprot thrift.TProtocol) (success bool, err thrift.TException) {\n\tname, _, seqId, err2 := iprot.ReadMessageBegin(ctx)\n\tif err2 != nil {\n\t\treturn false, thrift.WrapTException(err2)\n\t}\n\tif processor, ok := p.GetProcessorFunction(name); ok {\n\t\treturn processor.Process(ctx, seqId, iprot, oprot)\n\t}\n\tiprot.Skip(ctx, thrift.STRUCT)\n\tiprot.ReadMessageEnd(ctx)\n\tx17 := thrift.NewTApplicationException(thrift.UNKNOWN_METHOD, \"Unknown function \"+name)\n\toprot.WriteMessageBegin(ctx, name, thrift.EXCEPTION, seqId)\n\tx17.Write(ctx, oprot)\n\toprot.WriteMessageEnd(ctx)\n\toprot.Flush(ctx)\n\treturn false, x17\n\n}\n\ntype extensionProcessorPing struct {\n\thandler Extension\n}\n\nfunc (p *extensionProcessorPing) Process(ctx context.Context, seqId int32, iprot, oprot thrift.TProtocol) (success bool, err thrift.TException) {\n\targs := ExtensionPingArgs{}\n\tvar err2 error\n\tif err2 = args.Read(ctx, iprot); err2 != nil {\n\t\tiprot.ReadMessageEnd(ctx)\n\t\tx := thrift.NewTApplicationException(thrift.PROTOCOL_ERROR, err2.Error())\n\t\toprot.WriteMessageBegin(ctx, \"ping\", thrift.EXCEPTION, seqId)\n\t\tx.Write(ctx, oprot)\n\t\toprot.WriteMessageEnd(ctx)\n\t\toprot.Flush(ctx)\n\t\treturn false, thrift.WrapTException(err2)\n\t}\n\tiprot.ReadMessageEnd(ctx)\n\n\ttickerCancel := func() {}\n\t// Start a goroutine to do server side connectivity check.\n\tif thrift.ServerConnectivityCheckInterval > 0 {\n\t\tvar cancel context.CancelFunc\n\t\tctx, cancel = context.WithCancel(ctx)\n\t\tdefer cancel()\n\t\tvar tickerCtx context.Context\n\t\ttickerCtx, tickerCancel = context.WithCancel(context.Background())\n\t\tdefer tickerCancel()\n\t\tgo func(ctx context.Context, cancel context.CancelFunc) {\n\t\t\tticker := time.NewTicker(thrift.ServerConnectivityCheckInterval)\n\t\t\tdefer ticker.Stop()\n\t\t\tfor {\n\t\t\t\tselect {\n\t\t\t\tcase <-ctx.Done():\n\t\t\t\t\treturn\n\t\t\t\tcase <-ticker.C:\n\t\t\t\t\tif !iprot.Transport().IsOpen() {\n\t\t\t\t\t\tcancel()\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}(tickerCtx, cancel)\n\t}\n\n\tresult := ExtensionPingResult{}\n\tvar retval *ExtensionStatus\n\tif retval, err2 = p.handler.Ping(ctx); err2 != nil {\n\t\ttickerCancel()\n\t\tif err2 == thrift.ErrAbandonRequest {\n\t\t\treturn false, thrift.WrapTException(err2)\n\t\t}\n\t\tx := thrift.NewTApplicationException(thrift.INTERNAL_ERROR, \"Internal error processing ping: \"+err2.Error())\n\t\toprot.WriteMessageBegin(ctx, \"ping\", thrift.EXCEPTION, seqId)\n\t\tx.Write(ctx, oprot)\n\t\toprot.WriteMessageEnd(ctx)\n\t\toprot.Flush(ctx)\n\t\treturn true, thrift.WrapTException(err2)\n\t} else {\n\t\tresult.Success = retval\n\t}\n\ttickerCancel()\n\tif err2 = oprot.WriteMessageBegin(ctx, \"ping\", thrift.REPLY, seqId); err2 != nil {\n\t\terr = thrift.WrapTException(err2)\n\t}\n\tif err2 = result.Write(ctx, oprot); err == nil && err2 != nil {\n\t\terr = thrift.WrapTException(err2)\n\t}\n\tif err2 = oprot.WriteMessageEnd(ctx); err == nil && err2 != nil {\n\t\terr = thrift.WrapTException(err2)\n\t}\n\tif err2 = oprot.Flush(ctx); err == nil && err2 != nil {\n\t\terr = thrift.WrapTException(err2)\n\t}\n\tif err != nil {\n\t\treturn\n\t}\n\treturn true, err\n}\n\ntype extensionProcessorCall struct {\n\thandler Extension\n}\n\nfunc (p *extensionProcessorCall) Process(ctx context.Context, seqId int32, iprot, oprot thrift.TProtocol) (success bool, err thrift.TException) {\n\targs := ExtensionCallArgs{}\n\tvar err2 error\n\tif err2 = args.Read(ctx, iprot); err2 != nil {\n\t\tiprot.ReadMessageEnd(ctx)\n\t\tx := thrift.NewTApplicationException(thrift.PROTOCOL_ERROR, err2.Error())\n\t\toprot.WriteMessageBegin(ctx, \"call\", thrift.EXCEPTION, seqId)\n\t\tx.Write(ctx, oprot)\n\t\toprot.WriteMessageEnd(ctx)\n\t\toprot.Flush(ctx)\n\t\treturn false, thrift.WrapTException(err2)\n\t}\n\tiprot.ReadMessageEnd(ctx)\n\n\ttickerCancel := func() {}\n\t// Start a goroutine to do server side connectivity check.\n\tif thrift.ServerConnectivityCheckInterval > 0 {\n\t\tvar cancel context.CancelFunc\n\t\tctx, cancel = context.WithCancel(ctx)\n\t\tdefer cancel()\n\t\tvar tickerCtx context.Context\n\t\ttickerCtx, tickerCancel = context.WithCancel(context.Background())\n\t\tdefer tickerCancel()\n\t\tgo func(ctx context.Context, cancel context.CancelFunc) {\n\t\t\tticker := time.NewTicker(thrift.ServerConnectivityCheckInterval)\n\t\t\tdefer ticker.Stop()\n\t\t\tfor {\n\t\t\t\tselect {\n\t\t\t\tcase <-ctx.Done():\n\t\t\t\t\treturn\n\t\t\t\tcase <-ticker.C:\n\t\t\t\t\tif !iprot.Transport().IsOpen() {\n\t\t\t\t\t\tcancel()\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}(tickerCtx, cancel)\n\t}\n\n\tresult := ExtensionCallResult{}\n\tvar retval *ExtensionResponse\n\tif retval, err2 = p.handler.Call(ctx, args.Registry, args.Item, args.Request); err2 != nil {\n\t\ttickerCancel()\n\t\tif err2 == thrift.ErrAbandonRequest {\n\t\t\treturn false, thrift.WrapTException(err2)\n\t\t}\n\t\tx := thrift.NewTApplicationException(thrift.INTERNAL_ERROR, \"Internal error processing call: \"+err2.Error())\n\t\toprot.WriteMessageBegin(ctx, \"call\", thrift.EXCEPTION, seqId)\n\t\tx.Write(ctx, oprot)\n\t\toprot.WriteMessageEnd(ctx)\n\t\toprot.Flush(ctx)\n\t\treturn true, thrift.WrapTException(err2)\n\t} else {\n\t\tresult.Success = retval\n\t}\n\ttickerCancel()\n\tif err2 = oprot.WriteMessageBegin(ctx, \"call\", thrift.REPLY, seqId); err2 != nil {\n\t\terr = thrift.WrapTException(err2)\n\t}\n\tif err2 = result.Write(ctx, oprot); err == nil && err2 != nil {\n\t\terr = thrift.WrapTException(err2)\n\t}\n\tif err2 = oprot.WriteMessageEnd(ctx); err == nil && err2 != nil {\n\t\terr = thrift.WrapTException(err2)\n\t}\n\tif err2 = oprot.Flush(ctx); err == nil && err2 != nil {\n\t\terr = thrift.WrapTException(err2)\n\t}\n\tif err != nil {\n\t\treturn\n\t}\n\treturn true, err\n}\n\ntype extensionProcessorShutdown struct {\n\thandler Extension\n}\n\nfunc (p *extensionProcessorShutdown) Process(ctx context.Context, seqId int32, iprot, oprot thrift.TProtocol) (success bool, err thrift.TException) {\n\targs := ExtensionShutdownArgs{}\n\tvar err2 error\n\tif err2 = args.Read(ctx, iprot); err2 != nil {\n\t\tiprot.ReadMessageEnd(ctx)\n\t\tx := thrift.NewTApplicationException(thrift.PROTOCOL_ERROR, err2.Error())\n\t\toprot.WriteMessageBegin(ctx, \"shutdown\", thrift.EXCEPTION, seqId)\n\t\tx.Write(ctx, oprot)\n\t\toprot.WriteMessageEnd(ctx)\n\t\toprot.Flush(ctx)\n\t\treturn false, thrift.WrapTException(err2)\n\t}\n\tiprot.ReadMessageEnd(ctx)\n\n\ttickerCancel := func() {}\n\t// Start a goroutine to do server side connectivity check.\n\tif thrift.ServerConnectivityCheckInterval > 0 {\n\t\tvar cancel context.CancelFunc\n\t\tctx, cancel = context.WithCancel(ctx)\n\t\tdefer cancel()\n\t\tvar tickerCtx context.Context\n\t\ttickerCtx, tickerCancel = context.WithCancel(context.Background())\n\t\tdefer tickerCancel()\n\t\tgo func(ctx context.Context, cancel context.CancelFunc) {\n\t\t\tticker := time.NewTicker(thrift.ServerConnectivityCheckInterval)\n\t\t\tdefer ticker.Stop()\n\t\t\tfor {\n\t\t\t\tselect {\n\t\t\t\tcase <-ctx.Done():\n\t\t\t\t\treturn\n\t\t\t\tcase <-ticker.C:\n\t\t\t\t\tif !iprot.Transport().IsOpen() {\n\t\t\t\t\t\tcancel()\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}(tickerCtx, cancel)\n\t}\n\n\tresult := ExtensionShutdownResult{}\n\tif err2 = p.handler.Shutdown(ctx); err2 != nil {\n\t\ttickerCancel()\n\t\tif err2 == thrift.ErrAbandonRequest {\n\t\t\treturn false, thrift.WrapTException(err2)\n\t\t}\n\t\tx := thrift.NewTApplicationException(thrift.INTERNAL_ERROR, \"Internal error processing shutdown: \"+err2.Error())\n\t\toprot.WriteMessageBegin(ctx, \"shutdown\", thrift.EXCEPTION, seqId)\n\t\tx.Write(ctx, oprot)\n\t\toprot.WriteMessageEnd(ctx)\n\t\toprot.Flush(ctx)\n\t\treturn true, thrift.WrapTException(err2)\n\t}\n\ttickerCancel()\n\tif err2 = oprot.WriteMessageBegin(ctx, \"shutdown\", thrift.REPLY, seqId); err2 != nil {\n\t\terr = thrift.WrapTException(err2)\n\t}\n\tif err2 = result.Write(ctx, oprot); err == nil && err2 != nil {\n\t\terr = thrift.WrapTException(err2)\n\t}\n\tif err2 = oprot.WriteMessageEnd(ctx); err == nil && err2 != nil {\n\t\terr = thrift.WrapTException(err2)\n\t}\n\tif err2 = oprot.Flush(ctx); err == nil && err2 != nil {\n\t\terr = thrift.WrapTException(err2)\n\t}\n\tif err != nil {\n\t\treturn\n\t}\n\treturn true, err\n}\n\n// HELPER FUNCTIONS AND STRUCTURES\n\ntype ExtensionPingArgs struct {\n}\n\nfunc NewExtensionPingArgs() *ExtensionPingArgs {\n\treturn &ExtensionPingArgs{}\n}\n\nfunc (p *ExtensionPingArgs) Read(ctx context.Context, iprot thrift.TProtocol) error {\n\tif _, err := iprot.ReadStructBegin(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T read error: \", p), err)\n\t}\n\n\tfor {\n\t\t_, fieldTypeId, fieldId, err := iprot.ReadFieldBegin(ctx)\n\t\tif err != nil {\n\t\t\treturn thrift.PrependError(fmt.Sprintf(\"%T field %d read error: \", p, fieldId), err)\n\t\t}\n\t\tif fieldTypeId == thrift.STOP {\n\t\t\tbreak\n\t\t}\n\t\tif err := iprot.Skip(ctx, fieldTypeId); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := iprot.ReadFieldEnd(ctx); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif err := iprot.ReadStructEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T read struct end error: \", p), err)\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionPingArgs) Write(ctx context.Context, oprot thrift.TProtocol) error {\n\tif err := oprot.WriteStructBegin(ctx, \"ping_args\"); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write struct begin error: \", p), err)\n\t}\n\tif p != nil {\n\t}\n\tif err := oprot.WriteFieldStop(ctx); err != nil {\n\t\treturn thrift.PrependError(\"write field stop error: \", err)\n\t}\n\tif err := oprot.WriteStructEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(\"write struct stop error: \", err)\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionPingArgs) String() string {\n\tif p == nil {\n\t\treturn \"<nil>\"\n\t}\n\treturn fmt.Sprintf(\"ExtensionPingArgs(%+v)\", *p)\n}\n\n// Attributes:\n//  - Success\ntype ExtensionPingResult struct {\n\tSuccess *ExtensionStatus `thrift:\"success,0\" db:\"success\" json:\"success,omitempty\"`\n}\n\nfunc NewExtensionPingResult() *ExtensionPingResult {\n\treturn &ExtensionPingResult{}\n}\n\nvar ExtensionPingResult_Success_DEFAULT *ExtensionStatus\n\nfunc (p *ExtensionPingResult) GetSuccess() *ExtensionStatus {\n\tif !p.IsSetSuccess() {\n\t\treturn ExtensionPingResult_Success_DEFAULT\n\t}\n\treturn p.Success\n}\nfunc (p *ExtensionPingResult) IsSetSuccess() bool {\n\treturn p.Success != nil\n}\n\nfunc (p *ExtensionPingResult) Read(ctx context.Context, iprot thrift.TProtocol) error {\n\tif _, err := iprot.ReadStructBegin(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T read error: \", p), err)\n\t}\n\n\tfor {\n\t\t_, fieldTypeId, fieldId, err := iprot.ReadFieldBegin(ctx)\n\t\tif err != nil {\n\t\t\treturn thrift.PrependError(fmt.Sprintf(\"%T field %d read error: \", p, fieldId), err)\n\t\t}\n\t\tif fieldTypeId == thrift.STOP {\n\t\t\tbreak\n\t\t}\n\t\tswitch fieldId {\n\t\tcase 0:\n\t\t\tif fieldTypeId == thrift.STRUCT {\n\t\t\t\tif err := p.ReadField0(ctx, iprot); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := iprot.Skip(ctx, fieldTypeId); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tif err := iprot.Skip(ctx, fieldTypeId); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\tif err := iprot.ReadFieldEnd(ctx); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif err := iprot.ReadStructEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T read struct end error: \", p), err)\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionPingResult) ReadField0(ctx context.Context, iprot thrift.TProtocol) error {\n\tp.Success = &ExtensionStatus{}\n\tif err := p.Success.Read(ctx, iprot); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T error reading struct: \", p.Success), err)\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionPingResult) Write(ctx context.Context, oprot thrift.TProtocol) error {\n\tif err := oprot.WriteStructBegin(ctx, \"ping_result\"); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write struct begin error: \", p), err)\n\t}\n\tif p != nil {\n\t\tif err := p.writeField0(ctx, oprot); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif err := oprot.WriteFieldStop(ctx); err != nil {\n\t\treturn thrift.PrependError(\"write field stop error: \", err)\n\t}\n\tif err := oprot.WriteStructEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(\"write struct stop error: \", err)\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionPingResult) writeField0(ctx context.Context, oprot thrift.TProtocol) (err error) {\n\tif p.IsSetSuccess() {\n\t\tif err := oprot.WriteFieldBegin(ctx, \"success\", thrift.STRUCT, 0); err != nil {\n\t\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write field begin error 0:success: \", p), err)\n\t\t}\n\t\tif err := p.Success.Write(ctx, oprot); err != nil {\n\t\t\treturn thrift.PrependError(fmt.Sprintf(\"%T error writing struct: \", p.Success), err)\n\t\t}\n\t\tif err := oprot.WriteFieldEnd(ctx); err != nil {\n\t\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write field end error 0:success: \", p), err)\n\t\t}\n\t}\n\treturn err\n}\n\nfunc (p *ExtensionPingResult) String() string {\n\tif p == nil {\n\t\treturn \"<nil>\"\n\t}\n\treturn fmt.Sprintf(\"ExtensionPingResult(%+v)\", *p)\n}\n\n// Attributes:\n//  - Registry\n//  - Item\n//  - Request\ntype ExtensionCallArgs struct {\n\tRegistry string                 `thrift:\"registry,1\" db:\"registry\" json:\"registry\"`\n\tItem     string                 `thrift:\"item,2\" db:\"item\" json:\"item\"`\n\tRequest  ExtensionPluginRequest `thrift:\"request,3\" db:\"request\" json:\"request\"`\n}\n\nfunc NewExtensionCallArgs() *ExtensionCallArgs {\n\treturn &ExtensionCallArgs{}\n}\n\nfunc (p *ExtensionCallArgs) GetRegistry() string {\n\treturn p.Registry\n}\n\nfunc (p *ExtensionCallArgs) GetItem() string {\n\treturn p.Item\n}\n\nfunc (p *ExtensionCallArgs) GetRequest() ExtensionPluginRequest {\n\treturn p.Request\n}\nfunc (p *ExtensionCallArgs) Read(ctx context.Context, iprot thrift.TProtocol) error {\n\tif _, err := iprot.ReadStructBegin(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T read error: \", p), err)\n\t}\n\n\tfor {\n\t\t_, fieldTypeId, fieldId, err := iprot.ReadFieldBegin(ctx)\n\t\tif err != nil {\n\t\t\treturn thrift.PrependError(fmt.Sprintf(\"%T field %d read error: \", p, fieldId), err)\n\t\t}\n\t\tif fieldTypeId == thrift.STOP {\n\t\t\tbreak\n\t\t}\n\t\tswitch fieldId {\n\t\tcase 1:\n\t\t\tif fieldTypeId == thrift.STRING {\n\t\t\t\tif err := p.ReadField1(ctx, iprot); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := iprot.Skip(ctx, fieldTypeId); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif fieldTypeId == thrift.STRING {\n\t\t\t\tif err := p.ReadField2(ctx, iprot); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := iprot.Skip(ctx, fieldTypeId); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\tcase 3:\n\t\t\tif fieldTypeId == thrift.MAP {\n\t\t\t\tif err := p.ReadField3(ctx, iprot); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := iprot.Skip(ctx, fieldTypeId); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tif err := iprot.Skip(ctx, fieldTypeId); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\tif err := iprot.ReadFieldEnd(ctx); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif err := iprot.ReadStructEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T read struct end error: \", p), err)\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionCallArgs) ReadField1(ctx context.Context, iprot thrift.TProtocol) error {\n\tif v, err := iprot.ReadString(ctx); err != nil {\n\t\treturn thrift.PrependError(\"error reading field 1: \", err)\n\t} else {\n\t\tp.Registry = v\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionCallArgs) ReadField2(ctx context.Context, iprot thrift.TProtocol) error {\n\tif v, err := iprot.ReadString(ctx); err != nil {\n\t\treturn thrift.PrependError(\"error reading field 2: \", err)\n\t} else {\n\t\tp.Item = v\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionCallArgs) ReadField3(ctx context.Context, iprot thrift.TProtocol) error {\n\t_, _, size, err := iprot.ReadMapBegin(ctx)\n\tif err != nil {\n\t\treturn thrift.PrependError(\"error reading map begin: \", err)\n\t}\n\ttMap := make(ExtensionPluginRequest, size)\n\tp.Request = tMap\n\tfor i := 0; i < size; i++ {\n\t\tvar _key18 string\n\t\tif v, err := iprot.ReadString(ctx); err != nil {\n\t\t\treturn thrift.PrependError(\"error reading field 0: \", err)\n\t\t} else {\n\t\t\t_key18 = v\n\t\t}\n\t\tvar _val19 string\n\t\tif v, err := iprot.ReadString(ctx); err != nil {\n\t\t\treturn thrift.PrependError(\"error reading field 0: \", err)\n\t\t} else {\n\t\t\t_val19 = v\n\t\t}\n\t\tp.Request[_key18] = _val19\n\t}\n\tif err := iprot.ReadMapEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(\"error reading map end: \", err)\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionCallArgs) Write(ctx context.Context, oprot thrift.TProtocol) error {\n\tif err := oprot.WriteStructBegin(ctx, \"call_args\"); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write struct begin error: \", p), err)\n\t}\n\tif p != nil {\n\t\tif err := p.writeField1(ctx, oprot); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := p.writeField2(ctx, oprot); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := p.writeField3(ctx, oprot); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif err := oprot.WriteFieldStop(ctx); err != nil {\n\t\treturn thrift.PrependError(\"write field stop error: \", err)\n\t}\n\tif err := oprot.WriteStructEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(\"write struct stop error: \", err)\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionCallArgs) writeField1(ctx context.Context, oprot thrift.TProtocol) (err error) {\n\tif err := oprot.WriteFieldBegin(ctx, \"registry\", thrift.STRING, 1); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write field begin error 1:registry: \", p), err)\n\t}\n\tif err := oprot.WriteString(ctx, string(p.Registry)); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T.registry (1) field write error: \", p), err)\n\t}\n\tif err := oprot.WriteFieldEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write field end error 1:registry: \", p), err)\n\t}\n\treturn err\n}\n\nfunc (p *ExtensionCallArgs) writeField2(ctx context.Context, oprot thrift.TProtocol) (err error) {\n\tif err := oprot.WriteFieldBegin(ctx, \"item\", thrift.STRING, 2); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write field begin error 2:item: \", p), err)\n\t}\n\tif err := oprot.WriteString(ctx, string(p.Item)); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T.item (2) field write error: \", p), err)\n\t}\n\tif err := oprot.WriteFieldEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write field end error 2:item: \", p), err)\n\t}\n\treturn err\n}\n\nfunc (p *ExtensionCallArgs) writeField3(ctx context.Context, oprot thrift.TProtocol) (err error) {\n\tif err := oprot.WriteFieldBegin(ctx, \"request\", thrift.MAP, 3); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write field begin error 3:request: \", p), err)\n\t}\n\tif err := oprot.WriteMapBegin(ctx, thrift.STRING, thrift.STRING, len(p.Request)); err != nil {\n\t\treturn thrift.PrependError(\"error writing map begin: \", err)\n\t}\n\tfor k, v := range p.Request {\n\t\tif err := oprot.WriteString(ctx, string(k)); err != nil {\n\t\t\treturn thrift.PrependError(fmt.Sprintf(\"%T. (0) field write error: \", p), err)\n\t\t}\n\t\tif err := oprot.WriteString(ctx, string(v)); err != nil {\n\t\t\treturn thrift.PrependError(fmt.Sprintf(\"%T. (0) field write error: \", p), err)\n\t\t}\n\t}\n\tif err := oprot.WriteMapEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(\"error writing map end: \", err)\n\t}\n\tif err := oprot.WriteFieldEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write field end error 3:request: \", p), err)\n\t}\n\treturn err\n}\n\nfunc (p *ExtensionCallArgs) String() string {\n\tif p == nil {\n\t\treturn \"<nil>\"\n\t}\n\treturn fmt.Sprintf(\"ExtensionCallArgs(%+v)\", *p)\n}\n\n// Attributes:\n//  - Success\ntype ExtensionCallResult struct {\n\tSuccess *ExtensionResponse `thrift:\"success,0\" db:\"success\" json:\"success,omitempty\"`\n}\n\nfunc NewExtensionCallResult() *ExtensionCallResult {\n\treturn &ExtensionCallResult{}\n}\n\nvar ExtensionCallResult_Success_DEFAULT *ExtensionResponse\n\nfunc (p *ExtensionCallResult) GetSuccess() *ExtensionResponse {\n\tif !p.IsSetSuccess() {\n\t\treturn ExtensionCallResult_Success_DEFAULT\n\t}\n\treturn p.Success\n}\nfunc (p *ExtensionCallResult) IsSetSuccess() bool {\n\treturn p.Success != nil\n}\n\nfunc (p *ExtensionCallResult) Read(ctx context.Context, iprot thrift.TProtocol) error {\n\tif _, err := iprot.ReadStructBegin(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T read error: \", p), err)\n\t}\n\n\tfor {\n\t\t_, fieldTypeId, fieldId, err := iprot.ReadFieldBegin(ctx)\n\t\tif err != nil {\n\t\t\treturn thrift.PrependError(fmt.Sprintf(\"%T field %d read error: \", p, fieldId), err)\n\t\t}\n\t\tif fieldTypeId == thrift.STOP {\n\t\t\tbreak\n\t\t}\n\t\tswitch fieldId {\n\t\tcase 0:\n\t\t\tif fieldTypeId == thrift.STRUCT {\n\t\t\t\tif err := p.ReadField0(ctx, iprot); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := iprot.Skip(ctx, fieldTypeId); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tif err := iprot.Skip(ctx, fieldTypeId); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\tif err := iprot.ReadFieldEnd(ctx); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif err := iprot.ReadStructEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T read struct end error: \", p), err)\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionCallResult) ReadField0(ctx context.Context, iprot thrift.TProtocol) error {\n\tp.Success = &ExtensionResponse{}\n\tif err := p.Success.Read(ctx, iprot); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T error reading struct: \", p.Success), err)\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionCallResult) Write(ctx context.Context, oprot thrift.TProtocol) error {\n\tif err := oprot.WriteStructBegin(ctx, \"call_result\"); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write struct begin error: \", p), err)\n\t}\n\tif p != nil {\n\t\tif err := p.writeField0(ctx, oprot); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif err := oprot.WriteFieldStop(ctx); err != nil {\n\t\treturn thrift.PrependError(\"write field stop error: \", err)\n\t}\n\tif err := oprot.WriteStructEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(\"write struct stop error: \", err)\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionCallResult) writeField0(ctx context.Context, oprot thrift.TProtocol) (err error) {\n\tif p.IsSetSuccess() {\n\t\tif err := oprot.WriteFieldBegin(ctx, \"success\", thrift.STRUCT, 0); err != nil {\n\t\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write field begin error 0:success: \", p), err)\n\t\t}\n\t\tif err := p.Success.Write(ctx, oprot); err != nil {\n\t\t\treturn thrift.PrependError(fmt.Sprintf(\"%T error writing struct: \", p.Success), err)\n\t\t}\n\t\tif err := oprot.WriteFieldEnd(ctx); err != nil {\n\t\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write field end error 0:success: \", p), err)\n\t\t}\n\t}\n\treturn err\n}\n\nfunc (p *ExtensionCallResult) String() string {\n\tif p == nil {\n\t\treturn \"<nil>\"\n\t}\n\treturn fmt.Sprintf(\"ExtensionCallResult(%+v)\", *p)\n}\n\ntype ExtensionShutdownArgs struct {\n}\n\nfunc NewExtensionShutdownArgs() *ExtensionShutdownArgs {\n\treturn &ExtensionShutdownArgs{}\n}\n\nfunc (p *ExtensionShutdownArgs) Read(ctx context.Context, iprot thrift.TProtocol) error {\n\tif _, err := iprot.ReadStructBegin(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T read error: \", p), err)\n\t}\n\n\tfor {\n\t\t_, fieldTypeId, fieldId, err := iprot.ReadFieldBegin(ctx)\n\t\tif err != nil {\n\t\t\treturn thrift.PrependError(fmt.Sprintf(\"%T field %d read error: \", p, fieldId), err)\n\t\t}\n\t\tif fieldTypeId == thrift.STOP {\n\t\t\tbreak\n\t\t}\n\t\tif err := iprot.Skip(ctx, fieldTypeId); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := iprot.ReadFieldEnd(ctx); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif err := iprot.ReadStructEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T read struct end error: \", p), err)\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionShutdownArgs) Write(ctx context.Context, oprot thrift.TProtocol) error {\n\tif err := oprot.WriteStructBegin(ctx, \"shutdown_args\"); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write struct begin error: \", p), err)\n\t}\n\tif p != nil {\n\t}\n\tif err := oprot.WriteFieldStop(ctx); err != nil {\n\t\treturn thrift.PrependError(\"write field stop error: \", err)\n\t}\n\tif err := oprot.WriteStructEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(\"write struct stop error: \", err)\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionShutdownArgs) String() string {\n\tif p == nil {\n\t\treturn \"<nil>\"\n\t}\n\treturn fmt.Sprintf(\"ExtensionShutdownArgs(%+v)\", *p)\n}\n\ntype ExtensionShutdownResult struct {\n}\n\nfunc NewExtensionShutdownResult() *ExtensionShutdownResult {\n\treturn &ExtensionShutdownResult{}\n}\n\nfunc (p *ExtensionShutdownResult) Read(ctx context.Context, iprot thrift.TProtocol) error {\n\tif _, err := iprot.ReadStructBegin(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T read error: \", p), err)\n\t}\n\n\tfor {\n\t\t_, fieldTypeId, fieldId, err := iprot.ReadFieldBegin(ctx)\n\t\tif err != nil {\n\t\t\treturn thrift.PrependError(fmt.Sprintf(\"%T field %d read error: \", p, fieldId), err)\n\t\t}\n\t\tif fieldTypeId == thrift.STOP {\n\t\t\tbreak\n\t\t}\n\t\tif err := iprot.Skip(ctx, fieldTypeId); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := iprot.ReadFieldEnd(ctx); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif err := iprot.ReadStructEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T read struct end error: \", p), err)\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionShutdownResult) Write(ctx context.Context, oprot thrift.TProtocol) error {\n\tif err := oprot.WriteStructBegin(ctx, \"shutdown_result\"); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write struct begin error: \", p), err)\n\t}\n\tif p != nil {\n\t}\n\tif err := oprot.WriteFieldStop(ctx); err != nil {\n\t\treturn thrift.PrependError(\"write field stop error: \", err)\n\t}\n\tif err := oprot.WriteStructEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(\"write struct stop error: \", err)\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionShutdownResult) String() string {\n\tif p == nil {\n\t\treturn \"<nil>\"\n\t}\n\treturn fmt.Sprintf(\"ExtensionShutdownResult(%+v)\", *p)\n}\n\ntype ExtensionManager interface {\n\tExtension\n\n\tExtensions(ctx context.Context) (_r InternalExtensionList, _err error)\n\tOptions(ctx context.Context) (_r InternalOptionList, _err error)\n\t// Parameters:\n\t//  - Info\n\t//  - Registry\n\tRegisterExtension(ctx context.Context, info *InternalExtensionInfo, registry ExtensionRegistry) (_r *ExtensionStatus, _err error)\n\t// Parameters:\n\t//  - UUID\n\tDeregisterExtension(ctx context.Context, uuid ExtensionRouteUUID) (_r *ExtensionStatus, _err error)\n\t// Parameters:\n\t//  - Sql\n\tQuery(ctx context.Context, sql string) (_r *ExtensionResponse, _err error)\n\t// Parameters:\n\t//  - Sql\n\tGetQueryColumns(ctx context.Context, sql string) (_r *ExtensionResponse, _err error)\n}\n\ntype ExtensionManagerClient struct {\n\t*ExtensionClient\n}\n\nfunc NewExtensionManagerClientFactory(t thrift.TTransport, f thrift.TProtocolFactory) *ExtensionManagerClient {\n\treturn &ExtensionManagerClient{ExtensionClient: NewExtensionClientFactory(t, f)}\n}\n\nfunc NewExtensionManagerClientProtocol(t thrift.TTransport, iprot thrift.TProtocol, oprot thrift.TProtocol) *ExtensionManagerClient {\n\treturn &ExtensionManagerClient{ExtensionClient: NewExtensionClientProtocol(t, iprot, oprot)}\n}\n\nfunc NewExtensionManagerClient(c thrift.TClient) *ExtensionManagerClient {\n\treturn &ExtensionManagerClient{\n\t\tExtensionClient: NewExtensionClient(c),\n\t}\n}\n\nfunc (p *ExtensionManagerClient) Extensions(ctx context.Context) (_r InternalExtensionList, _err error) {\n\tvar _args28 ExtensionManagerExtensionsArgs\n\tvar _result30 ExtensionManagerExtensionsResult\n\tvar _meta29 thrift.ResponseMeta\n\t_meta29, _err = p.Client_().Call(ctx, \"extensions\", &_args28, &_result30)\n\tp.SetLastResponseMeta_(_meta29)\n\tif _err != nil {\n\t\treturn\n\t}\n\treturn _result30.GetSuccess(), nil\n}\n\nfunc (p *ExtensionManagerClient) Options(ctx context.Context) (_r InternalOptionList, _err error) {\n\tvar _args31 ExtensionManagerOptionsArgs\n\tvar _result33 ExtensionManagerOptionsResult\n\tvar _meta32 thrift.ResponseMeta\n\t_meta32, _err = p.Client_().Call(ctx, \"options\", &_args31, &_result33)\n\tp.SetLastResponseMeta_(_meta32)\n\tif _err != nil {\n\t\treturn\n\t}\n\treturn _result33.GetSuccess(), nil\n}\n\n// Parameters:\n//  - Info\n//  - Registry\nfunc (p *ExtensionManagerClient) RegisterExtension(ctx context.Context, info *InternalExtensionInfo, registry ExtensionRegistry) (_r *ExtensionStatus, _err error) {\n\tvar _args34 ExtensionManagerRegisterExtensionArgs\n\t_args34.Info = info\n\t_args34.Registry = registry\n\tvar _result36 ExtensionManagerRegisterExtensionResult\n\tvar _meta35 thrift.ResponseMeta\n\t_meta35, _err = p.Client_().Call(ctx, \"registerExtension\", &_args34, &_result36)\n\tp.SetLastResponseMeta_(_meta35)\n\tif _err != nil {\n\t\treturn\n\t}\n\tif _ret37 := _result36.GetSuccess(); _ret37 != nil {\n\t\treturn _ret37, nil\n\t}\n\treturn nil, thrift.NewTApplicationException(thrift.MISSING_RESULT, \"registerExtension failed: unknown result\")\n}\n\n// Parameters:\n//  - UUID\nfunc (p *ExtensionManagerClient) DeregisterExtension(ctx context.Context, uuid ExtensionRouteUUID) (_r *ExtensionStatus, _err error) {\n\tvar _args38 ExtensionManagerDeregisterExtensionArgs\n\t_args38.UUID = uuid\n\tvar _result40 ExtensionManagerDeregisterExtensionResult\n\tvar _meta39 thrift.ResponseMeta\n\t_meta39, _err = p.Client_().Call(ctx, \"deregisterExtension\", &_args38, &_result40)\n\tp.SetLastResponseMeta_(_meta39)\n\tif _err != nil {\n\t\treturn\n\t}\n\tif _ret41 := _result40.GetSuccess(); _ret41 != nil {\n\t\treturn _ret41, nil\n\t}\n\treturn nil, thrift.NewTApplicationException(thrift.MISSING_RESULT, \"deregisterExtension failed: unknown result\")\n}\n\n// Parameters:\n//  - Sql\nfunc (p *ExtensionManagerClient) Query(ctx context.Context, sql string) (_r *ExtensionResponse, _err error) {\n\tvar _args42 ExtensionManagerQueryArgs\n\t_args42.Sql = sql\n\tvar _result44 ExtensionManagerQueryResult\n\tvar _meta43 thrift.ResponseMeta\n\t_meta43, _err = p.Client_().Call(ctx, \"query\", &_args42, &_result44)\n\tp.SetLastResponseMeta_(_meta43)\n\tif _err != nil {\n\t\treturn\n\t}\n\tif _ret45 := _result44.GetSuccess(); _ret45 != nil {\n\t\treturn _ret45, nil\n\t}\n\treturn nil, thrift.NewTApplicationException(thrift.MISSING_RESULT, \"query failed: unknown result\")\n}\n\n// Parameters:\n//  - Sql\nfunc (p *ExtensionManagerClient) GetQueryColumns(ctx context.Context, sql string) (_r *ExtensionResponse, _err error) {\n\tvar _args46 ExtensionManagerGetQueryColumnsArgs\n\t_args46.Sql = sql\n\tvar _result48 ExtensionManagerGetQueryColumnsResult\n\tvar _meta47 thrift.ResponseMeta\n\t_meta47, _err = p.Client_().Call(ctx, \"getQueryColumns\", &_args46, &_result48)\n\tp.SetLastResponseMeta_(_meta47)\n\tif _err != nil {\n\t\treturn\n\t}\n\tif _ret49 := _result48.GetSuccess(); _ret49 != nil {\n\t\treturn _ret49, nil\n\t}\n\treturn nil, thrift.NewTApplicationException(thrift.MISSING_RESULT, \"getQueryColumns failed: unknown result\")\n}\n\ntype ExtensionManagerProcessor struct {\n\t*ExtensionProcessor\n}\n\nfunc NewExtensionManagerProcessor(handler ExtensionManager) *ExtensionManagerProcessor {\n\tself50 := &ExtensionManagerProcessor{NewExtensionProcessor(handler)}\n\tself50.AddToProcessorMap(\"extensions\", &extensionManagerProcessorExtensions{handler: handler})\n\tself50.AddToProcessorMap(\"options\", &extensionManagerProcessorOptions{handler: handler})\n\tself50.AddToProcessorMap(\"registerExtension\", &extensionManagerProcessorRegisterExtension{handler: handler})\n\tself50.AddToProcessorMap(\"deregisterExtension\", &extensionManagerProcessorDeregisterExtension{handler: handler})\n\tself50.AddToProcessorMap(\"query\", &extensionManagerProcessorQuery{handler: handler})\n\tself50.AddToProcessorMap(\"getQueryColumns\", &extensionManagerProcessorGetQueryColumns{handler: handler})\n\treturn self50\n}\n\ntype extensionManagerProcessorExtensions struct {\n\thandler ExtensionManager\n}\n\nfunc (p *extensionManagerProcessorExtensions) Process(ctx context.Context, seqId int32, iprot, oprot thrift.TProtocol) (success bool, err thrift.TException) {\n\targs := ExtensionManagerExtensionsArgs{}\n\tvar err2 error\n\tif err2 = args.Read(ctx, iprot); err2 != nil {\n\t\tiprot.ReadMessageEnd(ctx)\n\t\tx := thrift.NewTApplicationException(thrift.PROTOCOL_ERROR, err2.Error())\n\t\toprot.WriteMessageBegin(ctx, \"extensions\", thrift.EXCEPTION, seqId)\n\t\tx.Write(ctx, oprot)\n\t\toprot.WriteMessageEnd(ctx)\n\t\toprot.Flush(ctx)\n\t\treturn false, thrift.WrapTException(err2)\n\t}\n\tiprot.ReadMessageEnd(ctx)\n\n\ttickerCancel := func() {}\n\t// Start a goroutine to do server side connectivity check.\n\tif thrift.ServerConnectivityCheckInterval > 0 {\n\t\tvar cancel context.CancelFunc\n\t\tctx, cancel = context.WithCancel(ctx)\n\t\tdefer cancel()\n\t\tvar tickerCtx context.Context\n\t\ttickerCtx, tickerCancel = context.WithCancel(context.Background())\n\t\tdefer tickerCancel()\n\t\tgo func(ctx context.Context, cancel context.CancelFunc) {\n\t\t\tticker := time.NewTicker(thrift.ServerConnectivityCheckInterval)\n\t\t\tdefer ticker.Stop()\n\t\t\tfor {\n\t\t\t\tselect {\n\t\t\t\tcase <-ctx.Done():\n\t\t\t\t\treturn\n\t\t\t\tcase <-ticker.C:\n\t\t\t\t\tif !iprot.Transport().IsOpen() {\n\t\t\t\t\t\tcancel()\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}(tickerCtx, cancel)\n\t}\n\n\tresult := ExtensionManagerExtensionsResult{}\n\tvar retval InternalExtensionList\n\tif retval, err2 = p.handler.Extensions(ctx); err2 != nil {\n\t\ttickerCancel()\n\t\tif err2 == thrift.ErrAbandonRequest {\n\t\t\treturn false, thrift.WrapTException(err2)\n\t\t}\n\t\tx := thrift.NewTApplicationException(thrift.INTERNAL_ERROR, \"Internal error processing extensions: \"+err2.Error())\n\t\toprot.WriteMessageBegin(ctx, \"extensions\", thrift.EXCEPTION, seqId)\n\t\tx.Write(ctx, oprot)\n\t\toprot.WriteMessageEnd(ctx)\n\t\toprot.Flush(ctx)\n\t\treturn true, thrift.WrapTException(err2)\n\t} else {\n\t\tresult.Success = retval\n\t}\n\ttickerCancel()\n\tif err2 = oprot.WriteMessageBegin(ctx, \"extensions\", thrift.REPLY, seqId); err2 != nil {\n\t\terr = thrift.WrapTException(err2)\n\t}\n\tif err2 = result.Write(ctx, oprot); err == nil && err2 != nil {\n\t\terr = thrift.WrapTException(err2)\n\t}\n\tif err2 = oprot.WriteMessageEnd(ctx); err == nil && err2 != nil {\n\t\terr = thrift.WrapTException(err2)\n\t}\n\tif err2 = oprot.Flush(ctx); err == nil && err2 != nil {\n\t\terr = thrift.WrapTException(err2)\n\t}\n\tif err != nil {\n\t\treturn\n\t}\n\treturn true, err\n}\n\ntype extensionManagerProcessorOptions struct {\n\thandler ExtensionManager\n}\n\nfunc (p *extensionManagerProcessorOptions) Process(ctx context.Context, seqId int32, iprot, oprot thrift.TProtocol) (success bool, err thrift.TException) {\n\targs := ExtensionManagerOptionsArgs{}\n\tvar err2 error\n\tif err2 = args.Read(ctx, iprot); err2 != nil {\n\t\tiprot.ReadMessageEnd(ctx)\n\t\tx := thrift.NewTApplicationException(thrift.PROTOCOL_ERROR, err2.Error())\n\t\toprot.WriteMessageBegin(ctx, \"options\", thrift.EXCEPTION, seqId)\n\t\tx.Write(ctx, oprot)\n\t\toprot.WriteMessageEnd(ctx)\n\t\toprot.Flush(ctx)\n\t\treturn false, thrift.WrapTException(err2)\n\t}\n\tiprot.ReadMessageEnd(ctx)\n\n\ttickerCancel := func() {}\n\t// Start a goroutine to do server side connectivity check.\n\tif thrift.ServerConnectivityCheckInterval > 0 {\n\t\tvar cancel context.CancelFunc\n\t\tctx, cancel = context.WithCancel(ctx)\n\t\tdefer cancel()\n\t\tvar tickerCtx context.Context\n\t\ttickerCtx, tickerCancel = context.WithCancel(context.Background())\n\t\tdefer tickerCancel()\n\t\tgo func(ctx context.Context, cancel context.CancelFunc) {\n\t\t\tticker := time.NewTicker(thrift.ServerConnectivityCheckInterval)\n\t\t\tdefer ticker.Stop()\n\t\t\tfor {\n\t\t\t\tselect {\n\t\t\t\tcase <-ctx.Done():\n\t\t\t\t\treturn\n\t\t\t\tcase <-ticker.C:\n\t\t\t\t\tif !iprot.Transport().IsOpen() {\n\t\t\t\t\t\tcancel()\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}(tickerCtx, cancel)\n\t}\n\n\tresult := ExtensionManagerOptionsResult{}\n\tvar retval InternalOptionList\n\tif retval, err2 = p.handler.Options(ctx); err2 != nil {\n\t\ttickerCancel()\n\t\tif err2 == thrift.ErrAbandonRequest {\n\t\t\treturn false, thrift.WrapTException(err2)\n\t\t}\n\t\tx := thrift.NewTApplicationException(thrift.INTERNAL_ERROR, \"Internal error processing options: \"+err2.Error())\n\t\toprot.WriteMessageBegin(ctx, \"options\", thrift.EXCEPTION, seqId)\n\t\tx.Write(ctx, oprot)\n\t\toprot.WriteMessageEnd(ctx)\n\t\toprot.Flush(ctx)\n\t\treturn true, thrift.WrapTException(err2)\n\t} else {\n\t\tresult.Success = retval\n\t}\n\ttickerCancel()\n\tif err2 = oprot.WriteMessageBegin(ctx, \"options\", thrift.REPLY, seqId); err2 != nil {\n\t\terr = thrift.WrapTException(err2)\n\t}\n\tif err2 = result.Write(ctx, oprot); err == nil && err2 != nil {\n\t\terr = thrift.WrapTException(err2)\n\t}\n\tif err2 = oprot.WriteMessageEnd(ctx); err == nil && err2 != nil {\n\t\terr = thrift.WrapTException(err2)\n\t}\n\tif err2 = oprot.Flush(ctx); err == nil && err2 != nil {\n\t\terr = thrift.WrapTException(err2)\n\t}\n\tif err != nil {\n\t\treturn\n\t}\n\treturn true, err\n}\n\ntype extensionManagerProcessorRegisterExtension struct {\n\thandler ExtensionManager\n}\n\nfunc (p *extensionManagerProcessorRegisterExtension) Process(ctx context.Context, seqId int32, iprot, oprot thrift.TProtocol) (success bool, err thrift.TException) {\n\targs := ExtensionManagerRegisterExtensionArgs{}\n\tvar err2 error\n\tif err2 = args.Read(ctx, iprot); err2 != nil {\n\t\tiprot.ReadMessageEnd(ctx)\n\t\tx := thrift.NewTApplicationException(thrift.PROTOCOL_ERROR, err2.Error())\n\t\toprot.WriteMessageBegin(ctx, \"registerExtension\", thrift.EXCEPTION, seqId)\n\t\tx.Write(ctx, oprot)\n\t\toprot.WriteMessageEnd(ctx)\n\t\toprot.Flush(ctx)\n\t\treturn false, thrift.WrapTException(err2)\n\t}\n\tiprot.ReadMessageEnd(ctx)\n\n\ttickerCancel := func() {}\n\t// Start a goroutine to do server side connectivity check.\n\tif thrift.ServerConnectivityCheckInterval > 0 {\n\t\tvar cancel context.CancelFunc\n\t\tctx, cancel = context.WithCancel(ctx)\n\t\tdefer cancel()\n\t\tvar tickerCtx context.Context\n\t\ttickerCtx, tickerCancel = context.WithCancel(context.Background())\n\t\tdefer tickerCancel()\n\t\tgo func(ctx context.Context, cancel context.CancelFunc) {\n\t\t\tticker := time.NewTicker(thrift.ServerConnectivityCheckInterval)\n\t\t\tdefer ticker.Stop()\n\t\t\tfor {\n\t\t\t\tselect {\n\t\t\t\tcase <-ctx.Done():\n\t\t\t\t\treturn\n\t\t\t\tcase <-ticker.C:\n\t\t\t\t\tif !iprot.Transport().IsOpen() {\n\t\t\t\t\t\tcancel()\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}(tickerCtx, cancel)\n\t}\n\n\tresult := ExtensionManagerRegisterExtensionResult{}\n\tvar retval *ExtensionStatus\n\tif retval, err2 = p.handler.RegisterExtension(ctx, args.Info, args.Registry); err2 != nil {\n\t\ttickerCancel()\n\t\tif err2 == thrift.ErrAbandonRequest {\n\t\t\treturn false, thrift.WrapTException(err2)\n\t\t}\n\t\tx := thrift.NewTApplicationException(thrift.INTERNAL_ERROR, \"Internal error processing registerExtension: \"+err2.Error())\n\t\toprot.WriteMessageBegin(ctx, \"registerExtension\", thrift.EXCEPTION, seqId)\n\t\tx.Write(ctx, oprot)\n\t\toprot.WriteMessageEnd(ctx)\n\t\toprot.Flush(ctx)\n\t\treturn true, thrift.WrapTException(err2)\n\t} else {\n\t\tresult.Success = retval\n\t}\n\ttickerCancel()\n\tif err2 = oprot.WriteMessageBegin(ctx, \"registerExtension\", thrift.REPLY, seqId); err2 != nil {\n\t\terr = thrift.WrapTException(err2)\n\t}\n\tif err2 = result.Write(ctx, oprot); err == nil && err2 != nil {\n\t\terr = thrift.WrapTException(err2)\n\t}\n\tif err2 = oprot.WriteMessageEnd(ctx); err == nil && err2 != nil {\n\t\terr = thrift.WrapTException(err2)\n\t}\n\tif err2 = oprot.Flush(ctx); err == nil && err2 != nil {\n\t\terr = thrift.WrapTException(err2)\n\t}\n\tif err != nil {\n\t\treturn\n\t}\n\treturn true, err\n}\n\ntype extensionManagerProcessorDeregisterExtension struct {\n\thandler ExtensionManager\n}\n\nfunc (p *extensionManagerProcessorDeregisterExtension) Process(ctx context.Context, seqId int32, iprot, oprot thrift.TProtocol) (success bool, err thrift.TException) {\n\targs := ExtensionManagerDeregisterExtensionArgs{}\n\tvar err2 error\n\tif err2 = args.Read(ctx, iprot); err2 != nil {\n\t\tiprot.ReadMessageEnd(ctx)\n\t\tx := thrift.NewTApplicationException(thrift.PROTOCOL_ERROR, err2.Error())\n\t\toprot.WriteMessageBegin(ctx, \"deregisterExtension\", thrift.EXCEPTION, seqId)\n\t\tx.Write(ctx, oprot)\n\t\toprot.WriteMessageEnd(ctx)\n\t\toprot.Flush(ctx)\n\t\treturn false, thrift.WrapTException(err2)\n\t}\n\tiprot.ReadMessageEnd(ctx)\n\n\ttickerCancel := func() {}\n\t// Start a goroutine to do server side connectivity check.\n\tif thrift.ServerConnectivityCheckInterval > 0 {\n\t\tvar cancel context.CancelFunc\n\t\tctx, cancel = context.WithCancel(ctx)\n\t\tdefer cancel()\n\t\tvar tickerCtx context.Context\n\t\ttickerCtx, tickerCancel = context.WithCancel(context.Background())\n\t\tdefer tickerCancel()\n\t\tgo func(ctx context.Context, cancel context.CancelFunc) {\n\t\t\tticker := time.NewTicker(thrift.ServerConnectivityCheckInterval)\n\t\t\tdefer ticker.Stop()\n\t\t\tfor {\n\t\t\t\tselect {\n\t\t\t\tcase <-ctx.Done():\n\t\t\t\t\treturn\n\t\t\t\tcase <-ticker.C:\n\t\t\t\t\tif !iprot.Transport().IsOpen() {\n\t\t\t\t\t\tcancel()\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}(tickerCtx, cancel)\n\t}\n\n\tresult := ExtensionManagerDeregisterExtensionResult{}\n\tvar retval *ExtensionStatus\n\tif retval, err2 = p.handler.DeregisterExtension(ctx, args.UUID); err2 != nil {\n\t\ttickerCancel()\n\t\tif err2 == thrift.ErrAbandonRequest {\n\t\t\treturn false, thrift.WrapTException(err2)\n\t\t}\n\t\tx := thrift.NewTApplicationException(thrift.INTERNAL_ERROR, \"Internal error processing deregisterExtension: \"+err2.Error())\n\t\toprot.WriteMessageBegin(ctx, \"deregisterExtension\", thrift.EXCEPTION, seqId)\n\t\tx.Write(ctx, oprot)\n\t\toprot.WriteMessageEnd(ctx)\n\t\toprot.Flush(ctx)\n\t\treturn true, thrift.WrapTException(err2)\n\t} else {\n\t\tresult.Success = retval\n\t}\n\ttickerCancel()\n\tif err2 = oprot.WriteMessageBegin(ctx, \"deregisterExtension\", thrift.REPLY, seqId); err2 != nil {\n\t\terr = thrift.WrapTException(err2)\n\t}\n\tif err2 = result.Write(ctx, oprot); err == nil && err2 != nil {\n\t\terr = thrift.WrapTException(err2)\n\t}\n\tif err2 = oprot.WriteMessageEnd(ctx); err == nil && err2 != nil {\n\t\terr = thrift.WrapTException(err2)\n\t}\n\tif err2 = oprot.Flush(ctx); err == nil && err2 != nil {\n\t\terr = thrift.WrapTException(err2)\n\t}\n\tif err != nil {\n\t\treturn\n\t}\n\treturn true, err\n}\n\ntype extensionManagerProcessorQuery struct {\n\thandler ExtensionManager\n}\n\nfunc (p *extensionManagerProcessorQuery) Process(ctx context.Context, seqId int32, iprot, oprot thrift.TProtocol) (success bool, err thrift.TException) {\n\targs := ExtensionManagerQueryArgs{}\n\tvar err2 error\n\tif err2 = args.Read(ctx, iprot); err2 != nil {\n\t\tiprot.ReadMessageEnd(ctx)\n\t\tx := thrift.NewTApplicationException(thrift.PROTOCOL_ERROR, err2.Error())\n\t\toprot.WriteMessageBegin(ctx, \"query\", thrift.EXCEPTION, seqId)\n\t\tx.Write(ctx, oprot)\n\t\toprot.WriteMessageEnd(ctx)\n\t\toprot.Flush(ctx)\n\t\treturn false, thrift.WrapTException(err2)\n\t}\n\tiprot.ReadMessageEnd(ctx)\n\n\ttickerCancel := func() {}\n\t// Start a goroutine to do server side connectivity check.\n\tif thrift.ServerConnectivityCheckInterval > 0 {\n\t\tvar cancel context.CancelFunc\n\t\tctx, cancel = context.WithCancel(ctx)\n\t\tdefer cancel()\n\t\tvar tickerCtx context.Context\n\t\ttickerCtx, tickerCancel = context.WithCancel(context.Background())\n\t\tdefer tickerCancel()\n\t\tgo func(ctx context.Context, cancel context.CancelFunc) {\n\t\t\tticker := time.NewTicker(thrift.ServerConnectivityCheckInterval)\n\t\t\tdefer ticker.Stop()\n\t\t\tfor {\n\t\t\t\tselect {\n\t\t\t\tcase <-ctx.Done():\n\t\t\t\t\treturn\n\t\t\t\tcase <-ticker.C:\n\t\t\t\t\tif !iprot.Transport().IsOpen() {\n\t\t\t\t\t\tcancel()\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}(tickerCtx, cancel)\n\t}\n\n\tresult := ExtensionManagerQueryResult{}\n\tvar retval *ExtensionResponse\n\tif retval, err2 = p.handler.Query(ctx, args.Sql); err2 != nil {\n\t\ttickerCancel()\n\t\tif err2 == thrift.ErrAbandonRequest {\n\t\t\treturn false, thrift.WrapTException(err2)\n\t\t}\n\t\tx := thrift.NewTApplicationException(thrift.INTERNAL_ERROR, \"Internal error processing query: \"+err2.Error())\n\t\toprot.WriteMessageBegin(ctx, \"query\", thrift.EXCEPTION, seqId)\n\t\tx.Write(ctx, oprot)\n\t\toprot.WriteMessageEnd(ctx)\n\t\toprot.Flush(ctx)\n\t\treturn true, thrift.WrapTException(err2)\n\t} else {\n\t\tresult.Success = retval\n\t}\n\ttickerCancel()\n\tif err2 = oprot.WriteMessageBegin(ctx, \"query\", thrift.REPLY, seqId); err2 != nil {\n\t\terr = thrift.WrapTException(err2)\n\t}\n\tif err2 = result.Write(ctx, oprot); err == nil && err2 != nil {\n\t\terr = thrift.WrapTException(err2)\n\t}\n\tif err2 = oprot.WriteMessageEnd(ctx); err == nil && err2 != nil {\n\t\terr = thrift.WrapTException(err2)\n\t}\n\tif err2 = oprot.Flush(ctx); err == nil && err2 != nil {\n\t\terr = thrift.WrapTException(err2)\n\t}\n\tif err != nil {\n\t\treturn\n\t}\n\treturn true, err\n}\n\ntype extensionManagerProcessorGetQueryColumns struct {\n\thandler ExtensionManager\n}\n\nfunc (p *extensionManagerProcessorGetQueryColumns) Process(ctx context.Context, seqId int32, iprot, oprot thrift.TProtocol) (success bool, err thrift.TException) {\n\targs := ExtensionManagerGetQueryColumnsArgs{}\n\tvar err2 error\n\tif err2 = args.Read(ctx, iprot); err2 != nil {\n\t\tiprot.ReadMessageEnd(ctx)\n\t\tx := thrift.NewTApplicationException(thrift.PROTOCOL_ERROR, err2.Error())\n\t\toprot.WriteMessageBegin(ctx, \"getQueryColumns\", thrift.EXCEPTION, seqId)\n\t\tx.Write(ctx, oprot)\n\t\toprot.WriteMessageEnd(ctx)\n\t\toprot.Flush(ctx)\n\t\treturn false, thrift.WrapTException(err2)\n\t}\n\tiprot.ReadMessageEnd(ctx)\n\n\ttickerCancel := func() {}\n\t// Start a goroutine to do server side connectivity check.\n\tif thrift.ServerConnectivityCheckInterval > 0 {\n\t\tvar cancel context.CancelFunc\n\t\tctx, cancel = context.WithCancel(ctx)\n\t\tdefer cancel()\n\t\tvar tickerCtx context.Context\n\t\ttickerCtx, tickerCancel = context.WithCancel(context.Background())\n\t\tdefer tickerCancel()\n\t\tgo func(ctx context.Context, cancel context.CancelFunc) {\n\t\t\tticker := time.NewTicker(thrift.ServerConnectivityCheckInterval)\n\t\t\tdefer ticker.Stop()\n\t\t\tfor {\n\t\t\t\tselect {\n\t\t\t\tcase <-ctx.Done():\n\t\t\t\t\treturn\n\t\t\t\tcase <-ticker.C:\n\t\t\t\t\tif !iprot.Transport().IsOpen() {\n\t\t\t\t\t\tcancel()\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}(tickerCtx, cancel)\n\t}\n\n\tresult := ExtensionManagerGetQueryColumnsResult{}\n\tvar retval *ExtensionResponse\n\tif retval, err2 = p.handler.GetQueryColumns(ctx, args.Sql); err2 != nil {\n\t\ttickerCancel()\n\t\tif err2 == thrift.ErrAbandonRequest {\n\t\t\treturn false, thrift.WrapTException(err2)\n\t\t}\n\t\tx := thrift.NewTApplicationException(thrift.INTERNAL_ERROR, \"Internal error processing getQueryColumns: \"+err2.Error())\n\t\toprot.WriteMessageBegin(ctx, \"getQueryColumns\", thrift.EXCEPTION, seqId)\n\t\tx.Write(ctx, oprot)\n\t\toprot.WriteMessageEnd(ctx)\n\t\toprot.Flush(ctx)\n\t\treturn true, thrift.WrapTException(err2)\n\t} else {\n\t\tresult.Success = retval\n\t}\n\ttickerCancel()\n\tif err2 = oprot.WriteMessageBegin(ctx, \"getQueryColumns\", thrift.REPLY, seqId); err2 != nil {\n\t\terr = thrift.WrapTException(err2)\n\t}\n\tif err2 = result.Write(ctx, oprot); err == nil && err2 != nil {\n\t\terr = thrift.WrapTException(err2)\n\t}\n\tif err2 = oprot.WriteMessageEnd(ctx); err == nil && err2 != nil {\n\t\terr = thrift.WrapTException(err2)\n\t}\n\tif err2 = oprot.Flush(ctx); err == nil && err2 != nil {\n\t\terr = thrift.WrapTException(err2)\n\t}\n\tif err != nil {\n\t\treturn\n\t}\n\treturn true, err\n}\n\n// HELPER FUNCTIONS AND STRUCTURES\n\ntype ExtensionManagerExtensionsArgs struct {\n}\n\nfunc NewExtensionManagerExtensionsArgs() *ExtensionManagerExtensionsArgs {\n\treturn &ExtensionManagerExtensionsArgs{}\n}\n\nfunc (p *ExtensionManagerExtensionsArgs) Read(ctx context.Context, iprot thrift.TProtocol) error {\n\tif _, err := iprot.ReadStructBegin(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T read error: \", p), err)\n\t}\n\n\tfor {\n\t\t_, fieldTypeId, fieldId, err := iprot.ReadFieldBegin(ctx)\n\t\tif err != nil {\n\t\t\treturn thrift.PrependError(fmt.Sprintf(\"%T field %d read error: \", p, fieldId), err)\n\t\t}\n\t\tif fieldTypeId == thrift.STOP {\n\t\t\tbreak\n\t\t}\n\t\tif err := iprot.Skip(ctx, fieldTypeId); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := iprot.ReadFieldEnd(ctx); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif err := iprot.ReadStructEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T read struct end error: \", p), err)\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionManagerExtensionsArgs) Write(ctx context.Context, oprot thrift.TProtocol) error {\n\tif err := oprot.WriteStructBegin(ctx, \"extensions_args\"); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write struct begin error: \", p), err)\n\t}\n\tif p != nil {\n\t}\n\tif err := oprot.WriteFieldStop(ctx); err != nil {\n\t\treturn thrift.PrependError(\"write field stop error: \", err)\n\t}\n\tif err := oprot.WriteStructEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(\"write struct stop error: \", err)\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionManagerExtensionsArgs) String() string {\n\tif p == nil {\n\t\treturn \"<nil>\"\n\t}\n\treturn fmt.Sprintf(\"ExtensionManagerExtensionsArgs(%+v)\", *p)\n}\n\n// Attributes:\n//  - Success\ntype ExtensionManagerExtensionsResult struct {\n\tSuccess InternalExtensionList `thrift:\"success,0\" db:\"success\" json:\"success,omitempty\"`\n}\n\nfunc NewExtensionManagerExtensionsResult() *ExtensionManagerExtensionsResult {\n\treturn &ExtensionManagerExtensionsResult{}\n}\n\nvar ExtensionManagerExtensionsResult_Success_DEFAULT InternalExtensionList\n\nfunc (p *ExtensionManagerExtensionsResult) GetSuccess() InternalExtensionList {\n\treturn p.Success\n}\nfunc (p *ExtensionManagerExtensionsResult) IsSetSuccess() bool {\n\treturn p.Success != nil\n}\n\nfunc (p *ExtensionManagerExtensionsResult) Read(ctx context.Context, iprot thrift.TProtocol) error {\n\tif _, err := iprot.ReadStructBegin(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T read error: \", p), err)\n\t}\n\n\tfor {\n\t\t_, fieldTypeId, fieldId, err := iprot.ReadFieldBegin(ctx)\n\t\tif err != nil {\n\t\t\treturn thrift.PrependError(fmt.Sprintf(\"%T field %d read error: \", p, fieldId), err)\n\t\t}\n\t\tif fieldTypeId == thrift.STOP {\n\t\t\tbreak\n\t\t}\n\t\tswitch fieldId {\n\t\tcase 0:\n\t\t\tif fieldTypeId == thrift.MAP {\n\t\t\t\tif err := p.ReadField0(ctx, iprot); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := iprot.Skip(ctx, fieldTypeId); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tif err := iprot.Skip(ctx, fieldTypeId); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\tif err := iprot.ReadFieldEnd(ctx); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif err := iprot.ReadStructEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T read struct end error: \", p), err)\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionManagerExtensionsResult) ReadField0(ctx context.Context, iprot thrift.TProtocol) error {\n\t_, _, size, err := iprot.ReadMapBegin(ctx)\n\tif err != nil {\n\t\treturn thrift.PrependError(\"error reading map begin: \", err)\n\t}\n\ttMap := make(InternalExtensionList, size)\n\tp.Success = tMap\n\tfor i := 0; i < size; i++ {\n\t\tvar _key51 ExtensionRouteUUID\n\t\tif v, err := iprot.ReadI64(ctx); err != nil {\n\t\t\treturn thrift.PrependError(\"error reading field 0: \", err)\n\t\t} else {\n\t\t\ttemp := ExtensionRouteUUID(v)\n\t\t\t_key51 = temp\n\t\t}\n\t\t_val52 := &InternalExtensionInfo{}\n\t\tif err := _val52.Read(ctx, iprot); err != nil {\n\t\t\treturn thrift.PrependError(fmt.Sprintf(\"%T error reading struct: \", _val52), err)\n\t\t}\n\t\tp.Success[_key51] = _val52\n\t}\n\tif err := iprot.ReadMapEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(\"error reading map end: \", err)\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionManagerExtensionsResult) Write(ctx context.Context, oprot thrift.TProtocol) error {\n\tif err := oprot.WriteStructBegin(ctx, \"extensions_result\"); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write struct begin error: \", p), err)\n\t}\n\tif p != nil {\n\t\tif err := p.writeField0(ctx, oprot); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif err := oprot.WriteFieldStop(ctx); err != nil {\n\t\treturn thrift.PrependError(\"write field stop error: \", err)\n\t}\n\tif err := oprot.WriteStructEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(\"write struct stop error: \", err)\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionManagerExtensionsResult) writeField0(ctx context.Context, oprot thrift.TProtocol) (err error) {\n\tif p.IsSetSuccess() {\n\t\tif err := oprot.WriteFieldBegin(ctx, \"success\", thrift.MAP, 0); err != nil {\n\t\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write field begin error 0:success: \", p), err)\n\t\t}\n\t\tif err := oprot.WriteMapBegin(ctx, thrift.I64, thrift.STRUCT, len(p.Success)); err != nil {\n\t\t\treturn thrift.PrependError(\"error writing map begin: \", err)\n\t\t}\n\t\tfor k, v := range p.Success {\n\t\t\tif err := oprot.WriteI64(ctx, int64(k)); err != nil {\n\t\t\t\treturn thrift.PrependError(fmt.Sprintf(\"%T. (0) field write error: \", p), err)\n\t\t\t}\n\t\t\tif err := v.Write(ctx, oprot); err != nil {\n\t\t\t\treturn thrift.PrependError(fmt.Sprintf(\"%T error writing struct: \", v), err)\n\t\t\t}\n\t\t}\n\t\tif err := oprot.WriteMapEnd(ctx); err != nil {\n\t\t\treturn thrift.PrependError(\"error writing map end: \", err)\n\t\t}\n\t\tif err := oprot.WriteFieldEnd(ctx); err != nil {\n\t\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write field end error 0:success: \", p), err)\n\t\t}\n\t}\n\treturn err\n}\n\nfunc (p *ExtensionManagerExtensionsResult) String() string {\n\tif p == nil {\n\t\treturn \"<nil>\"\n\t}\n\treturn fmt.Sprintf(\"ExtensionManagerExtensionsResult(%+v)\", *p)\n}\n\ntype ExtensionManagerOptionsArgs struct {\n}\n\nfunc NewExtensionManagerOptionsArgs() *ExtensionManagerOptionsArgs {\n\treturn &ExtensionManagerOptionsArgs{}\n}\n\nfunc (p *ExtensionManagerOptionsArgs) Read(ctx context.Context, iprot thrift.TProtocol) error {\n\tif _, err := iprot.ReadStructBegin(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T read error: \", p), err)\n\t}\n\n\tfor {\n\t\t_, fieldTypeId, fieldId, err := iprot.ReadFieldBegin(ctx)\n\t\tif err != nil {\n\t\t\treturn thrift.PrependError(fmt.Sprintf(\"%T field %d read error: \", p, fieldId), err)\n\t\t}\n\t\tif fieldTypeId == thrift.STOP {\n\t\t\tbreak\n\t\t}\n\t\tif err := iprot.Skip(ctx, fieldTypeId); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := iprot.ReadFieldEnd(ctx); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif err := iprot.ReadStructEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T read struct end error: \", p), err)\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionManagerOptionsArgs) Write(ctx context.Context, oprot thrift.TProtocol) error {\n\tif err := oprot.WriteStructBegin(ctx, \"options_args\"); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write struct begin error: \", p), err)\n\t}\n\tif p != nil {\n\t}\n\tif err := oprot.WriteFieldStop(ctx); err != nil {\n\t\treturn thrift.PrependError(\"write field stop error: \", err)\n\t}\n\tif err := oprot.WriteStructEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(\"write struct stop error: \", err)\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionManagerOptionsArgs) String() string {\n\tif p == nil {\n\t\treturn \"<nil>\"\n\t}\n\treturn fmt.Sprintf(\"ExtensionManagerOptionsArgs(%+v)\", *p)\n}\n\n// Attributes:\n//  - Success\ntype ExtensionManagerOptionsResult struct {\n\tSuccess InternalOptionList `thrift:\"success,0\" db:\"success\" json:\"success,omitempty\"`\n}\n\nfunc NewExtensionManagerOptionsResult() *ExtensionManagerOptionsResult {\n\treturn &ExtensionManagerOptionsResult{}\n}\n\nvar ExtensionManagerOptionsResult_Success_DEFAULT InternalOptionList\n\nfunc (p *ExtensionManagerOptionsResult) GetSuccess() InternalOptionList {\n\treturn p.Success\n}\nfunc (p *ExtensionManagerOptionsResult) IsSetSuccess() bool {\n\treturn p.Success != nil\n}\n\nfunc (p *ExtensionManagerOptionsResult) Read(ctx context.Context, iprot thrift.TProtocol) error {\n\tif _, err := iprot.ReadStructBegin(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T read error: \", p), err)\n\t}\n\n\tfor {\n\t\t_, fieldTypeId, fieldId, err := iprot.ReadFieldBegin(ctx)\n\t\tif err != nil {\n\t\t\treturn thrift.PrependError(fmt.Sprintf(\"%T field %d read error: \", p, fieldId), err)\n\t\t}\n\t\tif fieldTypeId == thrift.STOP {\n\t\t\tbreak\n\t\t}\n\t\tswitch fieldId {\n\t\tcase 0:\n\t\t\tif fieldTypeId == thrift.MAP {\n\t\t\t\tif err := p.ReadField0(ctx, iprot); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := iprot.Skip(ctx, fieldTypeId); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tif err := iprot.Skip(ctx, fieldTypeId); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\tif err := iprot.ReadFieldEnd(ctx); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif err := iprot.ReadStructEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T read struct end error: \", p), err)\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionManagerOptionsResult) ReadField0(ctx context.Context, iprot thrift.TProtocol) error {\n\t_, _, size, err := iprot.ReadMapBegin(ctx)\n\tif err != nil {\n\t\treturn thrift.PrependError(\"error reading map begin: \", err)\n\t}\n\ttMap := make(InternalOptionList, size)\n\tp.Success = tMap\n\tfor i := 0; i < size; i++ {\n\t\tvar _key53 string\n\t\tif v, err := iprot.ReadString(ctx); err != nil {\n\t\t\treturn thrift.PrependError(\"error reading field 0: \", err)\n\t\t} else {\n\t\t\t_key53 = v\n\t\t}\n\t\t_val54 := &InternalOptionInfo{}\n\t\tif err := _val54.Read(ctx, iprot); err != nil {\n\t\t\treturn thrift.PrependError(fmt.Sprintf(\"%T error reading struct: \", _val54), err)\n\t\t}\n\t\tp.Success[_key53] = _val54\n\t}\n\tif err := iprot.ReadMapEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(\"error reading map end: \", err)\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionManagerOptionsResult) Write(ctx context.Context, oprot thrift.TProtocol) error {\n\tif err := oprot.WriteStructBegin(ctx, \"options_result\"); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write struct begin error: \", p), err)\n\t}\n\tif p != nil {\n\t\tif err := p.writeField0(ctx, oprot); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif err := oprot.WriteFieldStop(ctx); err != nil {\n\t\treturn thrift.PrependError(\"write field stop error: \", err)\n\t}\n\tif err := oprot.WriteStructEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(\"write struct stop error: \", err)\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionManagerOptionsResult) writeField0(ctx context.Context, oprot thrift.TProtocol) (err error) {\n\tif p.IsSetSuccess() {\n\t\tif err := oprot.WriteFieldBegin(ctx, \"success\", thrift.MAP, 0); err != nil {\n\t\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write field begin error 0:success: \", p), err)\n\t\t}\n\t\tif err := oprot.WriteMapBegin(ctx, thrift.STRING, thrift.STRUCT, len(p.Success)); err != nil {\n\t\t\treturn thrift.PrependError(\"error writing map begin: \", err)\n\t\t}\n\t\tfor k, v := range p.Success {\n\t\t\tif err := oprot.WriteString(ctx, string(k)); err != nil {\n\t\t\t\treturn thrift.PrependError(fmt.Sprintf(\"%T. (0) field write error: \", p), err)\n\t\t\t}\n\t\t\tif err := v.Write(ctx, oprot); err != nil {\n\t\t\t\treturn thrift.PrependError(fmt.Sprintf(\"%T error writing struct: \", v), err)\n\t\t\t}\n\t\t}\n\t\tif err := oprot.WriteMapEnd(ctx); err != nil {\n\t\t\treturn thrift.PrependError(\"error writing map end: \", err)\n\t\t}\n\t\tif err := oprot.WriteFieldEnd(ctx); err != nil {\n\t\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write field end error 0:success: \", p), err)\n\t\t}\n\t}\n\treturn err\n}\n\nfunc (p *ExtensionManagerOptionsResult) String() string {\n\tif p == nil {\n\t\treturn \"<nil>\"\n\t}\n\treturn fmt.Sprintf(\"ExtensionManagerOptionsResult(%+v)\", *p)\n}\n\n// Attributes:\n//  - Info\n//  - Registry\ntype ExtensionManagerRegisterExtensionArgs struct {\n\tInfo     *InternalExtensionInfo `thrift:\"info,1\" db:\"info\" json:\"info\"`\n\tRegistry ExtensionRegistry      `thrift:\"registry,2\" db:\"registry\" json:\"registry\"`\n}\n\nfunc NewExtensionManagerRegisterExtensionArgs() *ExtensionManagerRegisterExtensionArgs {\n\treturn &ExtensionManagerRegisterExtensionArgs{}\n}\n\nvar ExtensionManagerRegisterExtensionArgs_Info_DEFAULT *InternalExtensionInfo\n\nfunc (p *ExtensionManagerRegisterExtensionArgs) GetInfo() *InternalExtensionInfo {\n\tif !p.IsSetInfo() {\n\t\treturn ExtensionManagerRegisterExtensionArgs_Info_DEFAULT\n\t}\n\treturn p.Info\n}\n\nfunc (p *ExtensionManagerRegisterExtensionArgs) GetRegistry() ExtensionRegistry {\n\treturn p.Registry\n}\nfunc (p *ExtensionManagerRegisterExtensionArgs) IsSetInfo() bool {\n\treturn p.Info != nil\n}\n\nfunc (p *ExtensionManagerRegisterExtensionArgs) Read(ctx context.Context, iprot thrift.TProtocol) error {\n\tif _, err := iprot.ReadStructBegin(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T read error: \", p), err)\n\t}\n\n\tfor {\n\t\t_, fieldTypeId, fieldId, err := iprot.ReadFieldBegin(ctx)\n\t\tif err != nil {\n\t\t\treturn thrift.PrependError(fmt.Sprintf(\"%T field %d read error: \", p, fieldId), err)\n\t\t}\n\t\tif fieldTypeId == thrift.STOP {\n\t\t\tbreak\n\t\t}\n\t\tswitch fieldId {\n\t\tcase 1:\n\t\t\tif fieldTypeId == thrift.STRUCT {\n\t\t\t\tif err := p.ReadField1(ctx, iprot); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := iprot.Skip(ctx, fieldTypeId); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif fieldTypeId == thrift.MAP {\n\t\t\t\tif err := p.ReadField2(ctx, iprot); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := iprot.Skip(ctx, fieldTypeId); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tif err := iprot.Skip(ctx, fieldTypeId); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\tif err := iprot.ReadFieldEnd(ctx); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif err := iprot.ReadStructEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T read struct end error: \", p), err)\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionManagerRegisterExtensionArgs) ReadField1(ctx context.Context, iprot thrift.TProtocol) error {\n\tp.Info = &InternalExtensionInfo{}\n\tif err := p.Info.Read(ctx, iprot); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T error reading struct: \", p.Info), err)\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionManagerRegisterExtensionArgs) ReadField2(ctx context.Context, iprot thrift.TProtocol) error {\n\t_, _, size, err := iprot.ReadMapBegin(ctx)\n\tif err != nil {\n\t\treturn thrift.PrependError(\"error reading map begin: \", err)\n\t}\n\ttMap := make(ExtensionRegistry, size)\n\tp.Registry = tMap\n\tfor i := 0; i < size; i++ {\n\t\tvar _key55 string\n\t\tif v, err := iprot.ReadString(ctx); err != nil {\n\t\t\treturn thrift.PrependError(\"error reading field 0: \", err)\n\t\t} else {\n\t\t\t_key55 = v\n\t\t}\n\t\t_, _, size, err := iprot.ReadMapBegin(ctx)\n\t\tif err != nil {\n\t\t\treturn thrift.PrependError(\"error reading map begin: \", err)\n\t\t}\n\t\ttMap := make(ExtensionRouteTable, size)\n\t\t_val56 := tMap\n\t\tfor i := 0; i < size; i++ {\n\t\t\tvar _key57 string\n\t\t\tif v, err := iprot.ReadString(ctx); err != nil {\n\t\t\t\treturn thrift.PrependError(\"error reading field 0: \", err)\n\t\t\t} else {\n\t\t\t\t_key57 = v\n\t\t\t}\n\t\t\t_, size, err := iprot.ReadListBegin(ctx)\n\t\t\tif err != nil {\n\t\t\t\treturn thrift.PrependError(\"error reading list begin: \", err)\n\t\t\t}\n\t\t\ttSlice := make(ExtensionPluginResponse, 0, size)\n\t\t\t_val58 := tSlice\n\t\t\tfor i := 0; i < size; i++ {\n\t\t\t\t_, _, size, err := iprot.ReadMapBegin(ctx)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn thrift.PrependError(\"error reading map begin: \", err)\n\t\t\t\t}\n\t\t\t\ttMap := make(map[string]string, size)\n\t\t\t\t_elem59 := tMap\n\t\t\t\tfor i := 0; i < size; i++ {\n\t\t\t\t\tvar _key60 string\n\t\t\t\t\tif v, err := iprot.ReadString(ctx); err != nil {\n\t\t\t\t\t\treturn thrift.PrependError(\"error reading field 0: \", err)\n\t\t\t\t\t} else {\n\t\t\t\t\t\t_key60 = v\n\t\t\t\t\t}\n\t\t\t\t\tvar _val61 string\n\t\t\t\t\tif v, err := iprot.ReadString(ctx); err != nil {\n\t\t\t\t\t\treturn thrift.PrependError(\"error reading field 0: \", err)\n\t\t\t\t\t} else {\n\t\t\t\t\t\t_val61 = v\n\t\t\t\t\t}\n\t\t\t\t\t_elem59[_key60] = _val61\n\t\t\t\t}\n\t\t\t\tif err := iprot.ReadMapEnd(ctx); err != nil {\n\t\t\t\t\treturn thrift.PrependError(\"error reading map end: \", err)\n\t\t\t\t}\n\t\t\t\t_val58 = append(_val58, _elem59)\n\t\t\t}\n\t\t\tif err := iprot.ReadListEnd(ctx); err != nil {\n\t\t\t\treturn thrift.PrependError(\"error reading list end: \", err)\n\t\t\t}\n\t\t\t_val56[_key57] = _val58\n\t\t}\n\t\tif err := iprot.ReadMapEnd(ctx); err != nil {\n\t\t\treturn thrift.PrependError(\"error reading map end: \", err)\n\t\t}\n\t\tp.Registry[_key55] = _val56\n\t}\n\tif err := iprot.ReadMapEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(\"error reading map end: \", err)\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionManagerRegisterExtensionArgs) Write(ctx context.Context, oprot thrift.TProtocol) error {\n\tif err := oprot.WriteStructBegin(ctx, \"registerExtension_args\"); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write struct begin error: \", p), err)\n\t}\n\tif p != nil {\n\t\tif err := p.writeField1(ctx, oprot); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := p.writeField2(ctx, oprot); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif err := oprot.WriteFieldStop(ctx); err != nil {\n\t\treturn thrift.PrependError(\"write field stop error: \", err)\n\t}\n\tif err := oprot.WriteStructEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(\"write struct stop error: \", err)\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionManagerRegisterExtensionArgs) writeField1(ctx context.Context, oprot thrift.TProtocol) (err error) {\n\tif err := oprot.WriteFieldBegin(ctx, \"info\", thrift.STRUCT, 1); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write field begin error 1:info: \", p), err)\n\t}\n\tif err := p.Info.Write(ctx, oprot); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T error writing struct: \", p.Info), err)\n\t}\n\tif err := oprot.WriteFieldEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write field end error 1:info: \", p), err)\n\t}\n\treturn err\n}\n\nfunc (p *ExtensionManagerRegisterExtensionArgs) writeField2(ctx context.Context, oprot thrift.TProtocol) (err error) {\n\tif err := oprot.WriteFieldBegin(ctx, \"registry\", thrift.MAP, 2); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write field begin error 2:registry: \", p), err)\n\t}\n\tif err := oprot.WriteMapBegin(ctx, thrift.STRING, thrift.MAP, len(p.Registry)); err != nil {\n\t\treturn thrift.PrependError(\"error writing map begin: \", err)\n\t}\n\tfor k, v := range p.Registry {\n\t\tif err := oprot.WriteString(ctx, string(k)); err != nil {\n\t\t\treturn thrift.PrependError(fmt.Sprintf(\"%T. (0) field write error: \", p), err)\n\t\t}\n\t\tif err := oprot.WriteMapBegin(ctx, thrift.STRING, thrift.LIST, len(v)); err != nil {\n\t\t\treturn thrift.PrependError(\"error writing map begin: \", err)\n\t\t}\n\t\tfor k, v := range v {\n\t\t\tif err := oprot.WriteString(ctx, string(k)); err != nil {\n\t\t\t\treturn thrift.PrependError(fmt.Sprintf(\"%T. (0) field write error: \", p), err)\n\t\t\t}\n\t\t\tif err := oprot.WriteListBegin(ctx, thrift.MAP, len(v)); err != nil {\n\t\t\t\treturn thrift.PrependError(\"error writing list begin: \", err)\n\t\t\t}\n\t\t\tfor _, v := range v {\n\t\t\t\tif err := oprot.WriteMapBegin(ctx, thrift.STRING, thrift.STRING, len(v)); err != nil {\n\t\t\t\t\treturn thrift.PrependError(\"error writing map begin: \", err)\n\t\t\t\t}\n\t\t\t\tfor k, v := range v {\n\t\t\t\t\tif err := oprot.WriteString(ctx, string(k)); err != nil {\n\t\t\t\t\t\treturn thrift.PrependError(fmt.Sprintf(\"%T. (0) field write error: \", p), err)\n\t\t\t\t\t}\n\t\t\t\t\tif err := oprot.WriteString(ctx, string(v)); err != nil {\n\t\t\t\t\t\treturn thrift.PrependError(fmt.Sprintf(\"%T. (0) field write error: \", p), err)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif err := oprot.WriteMapEnd(ctx); err != nil {\n\t\t\t\t\treturn thrift.PrependError(\"error writing map end: \", err)\n\t\t\t\t}\n\t\t\t}\n\t\t\tif err := oprot.WriteListEnd(ctx); err != nil {\n\t\t\t\treturn thrift.PrependError(\"error writing list end: \", err)\n\t\t\t}\n\t\t}\n\t\tif err := oprot.WriteMapEnd(ctx); err != nil {\n\t\t\treturn thrift.PrependError(\"error writing map end: \", err)\n\t\t}\n\t}\n\tif err := oprot.WriteMapEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(\"error writing map end: \", err)\n\t}\n\tif err := oprot.WriteFieldEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write field end error 2:registry: \", p), err)\n\t}\n\treturn err\n}\n\nfunc (p *ExtensionManagerRegisterExtensionArgs) String() string {\n\tif p == nil {\n\t\treturn \"<nil>\"\n\t}\n\treturn fmt.Sprintf(\"ExtensionManagerRegisterExtensionArgs(%+v)\", *p)\n}\n\n// Attributes:\n//  - Success\ntype ExtensionManagerRegisterExtensionResult struct {\n\tSuccess *ExtensionStatus `thrift:\"success,0\" db:\"success\" json:\"success,omitempty\"`\n}\n\nfunc NewExtensionManagerRegisterExtensionResult() *ExtensionManagerRegisterExtensionResult {\n\treturn &ExtensionManagerRegisterExtensionResult{}\n}\n\nvar ExtensionManagerRegisterExtensionResult_Success_DEFAULT *ExtensionStatus\n\nfunc (p *ExtensionManagerRegisterExtensionResult) GetSuccess() *ExtensionStatus {\n\tif !p.IsSetSuccess() {\n\t\treturn ExtensionManagerRegisterExtensionResult_Success_DEFAULT\n\t}\n\treturn p.Success\n}\nfunc (p *ExtensionManagerRegisterExtensionResult) IsSetSuccess() bool {\n\treturn p.Success != nil\n}\n\nfunc (p *ExtensionManagerRegisterExtensionResult) Read(ctx context.Context, iprot thrift.TProtocol) error {\n\tif _, err := iprot.ReadStructBegin(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T read error: \", p), err)\n\t}\n\n\tfor {\n\t\t_, fieldTypeId, fieldId, err := iprot.ReadFieldBegin(ctx)\n\t\tif err != nil {\n\t\t\treturn thrift.PrependError(fmt.Sprintf(\"%T field %d read error: \", p, fieldId), err)\n\t\t}\n\t\tif fieldTypeId == thrift.STOP {\n\t\t\tbreak\n\t\t}\n\t\tswitch fieldId {\n\t\tcase 0:\n\t\t\tif fieldTypeId == thrift.STRUCT {\n\t\t\t\tif err := p.ReadField0(ctx, iprot); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := iprot.Skip(ctx, fieldTypeId); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tif err := iprot.Skip(ctx, fieldTypeId); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\tif err := iprot.ReadFieldEnd(ctx); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif err := iprot.ReadStructEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T read struct end error: \", p), err)\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionManagerRegisterExtensionResult) ReadField0(ctx context.Context, iprot thrift.TProtocol) error {\n\tp.Success = &ExtensionStatus{}\n\tif err := p.Success.Read(ctx, iprot); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T error reading struct: \", p.Success), err)\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionManagerRegisterExtensionResult) Write(ctx context.Context, oprot thrift.TProtocol) error {\n\tif err := oprot.WriteStructBegin(ctx, \"registerExtension_result\"); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write struct begin error: \", p), err)\n\t}\n\tif p != nil {\n\t\tif err := p.writeField0(ctx, oprot); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif err := oprot.WriteFieldStop(ctx); err != nil {\n\t\treturn thrift.PrependError(\"write field stop error: \", err)\n\t}\n\tif err := oprot.WriteStructEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(\"write struct stop error: \", err)\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionManagerRegisterExtensionResult) writeField0(ctx context.Context, oprot thrift.TProtocol) (err error) {\n\tif p.IsSetSuccess() {\n\t\tif err := oprot.WriteFieldBegin(ctx, \"success\", thrift.STRUCT, 0); err != nil {\n\t\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write field begin error 0:success: \", p), err)\n\t\t}\n\t\tif err := p.Success.Write(ctx, oprot); err != nil {\n\t\t\treturn thrift.PrependError(fmt.Sprintf(\"%T error writing struct: \", p.Success), err)\n\t\t}\n\t\tif err := oprot.WriteFieldEnd(ctx); err != nil {\n\t\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write field end error 0:success: \", p), err)\n\t\t}\n\t}\n\treturn err\n}\n\nfunc (p *ExtensionManagerRegisterExtensionResult) String() string {\n\tif p == nil {\n\t\treturn \"<nil>\"\n\t}\n\treturn fmt.Sprintf(\"ExtensionManagerRegisterExtensionResult(%+v)\", *p)\n}\n\n// Attributes:\n//  - UUID\ntype ExtensionManagerDeregisterExtensionArgs struct {\n\tUUID ExtensionRouteUUID `thrift:\"uuid,1\" db:\"uuid\" json:\"uuid\"`\n}\n\nfunc NewExtensionManagerDeregisterExtensionArgs() *ExtensionManagerDeregisterExtensionArgs {\n\treturn &ExtensionManagerDeregisterExtensionArgs{}\n}\n\nfunc (p *ExtensionManagerDeregisterExtensionArgs) GetUUID() ExtensionRouteUUID {\n\treturn p.UUID\n}\nfunc (p *ExtensionManagerDeregisterExtensionArgs) Read(ctx context.Context, iprot thrift.TProtocol) error {\n\tif _, err := iprot.ReadStructBegin(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T read error: \", p), err)\n\t}\n\n\tfor {\n\t\t_, fieldTypeId, fieldId, err := iprot.ReadFieldBegin(ctx)\n\t\tif err != nil {\n\t\t\treturn thrift.PrependError(fmt.Sprintf(\"%T field %d read error: \", p, fieldId), err)\n\t\t}\n\t\tif fieldTypeId == thrift.STOP {\n\t\t\tbreak\n\t\t}\n\t\tswitch fieldId {\n\t\tcase 1:\n\t\t\tif fieldTypeId == thrift.I64 {\n\t\t\t\tif err := p.ReadField1(ctx, iprot); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := iprot.Skip(ctx, fieldTypeId); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tif err := iprot.Skip(ctx, fieldTypeId); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\tif err := iprot.ReadFieldEnd(ctx); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif err := iprot.ReadStructEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T read struct end error: \", p), err)\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionManagerDeregisterExtensionArgs) ReadField1(ctx context.Context, iprot thrift.TProtocol) error {\n\tif v, err := iprot.ReadI64(ctx); err != nil {\n\t\treturn thrift.PrependError(\"error reading field 1: \", err)\n\t} else {\n\t\ttemp := ExtensionRouteUUID(v)\n\t\tp.UUID = temp\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionManagerDeregisterExtensionArgs) Write(ctx context.Context, oprot thrift.TProtocol) error {\n\tif err := oprot.WriteStructBegin(ctx, \"deregisterExtension_args\"); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write struct begin error: \", p), err)\n\t}\n\tif p != nil {\n\t\tif err := p.writeField1(ctx, oprot); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif err := oprot.WriteFieldStop(ctx); err != nil {\n\t\treturn thrift.PrependError(\"write field stop error: \", err)\n\t}\n\tif err := oprot.WriteStructEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(\"write struct stop error: \", err)\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionManagerDeregisterExtensionArgs) writeField1(ctx context.Context, oprot thrift.TProtocol) (err error) {\n\tif err := oprot.WriteFieldBegin(ctx, \"uuid\", thrift.I64, 1); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write field begin error 1:uuid: \", p), err)\n\t}\n\tif err := oprot.WriteI64(ctx, int64(p.UUID)); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T.uuid (1) field write error: \", p), err)\n\t}\n\tif err := oprot.WriteFieldEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write field end error 1:uuid: \", p), err)\n\t}\n\treturn err\n}\n\nfunc (p *ExtensionManagerDeregisterExtensionArgs) String() string {\n\tif p == nil {\n\t\treturn \"<nil>\"\n\t}\n\treturn fmt.Sprintf(\"ExtensionManagerDeregisterExtensionArgs(%+v)\", *p)\n}\n\n// Attributes:\n//  - Success\ntype ExtensionManagerDeregisterExtensionResult struct {\n\tSuccess *ExtensionStatus `thrift:\"success,0\" db:\"success\" json:\"success,omitempty\"`\n}\n\nfunc NewExtensionManagerDeregisterExtensionResult() *ExtensionManagerDeregisterExtensionResult {\n\treturn &ExtensionManagerDeregisterExtensionResult{}\n}\n\nvar ExtensionManagerDeregisterExtensionResult_Success_DEFAULT *ExtensionStatus\n\nfunc (p *ExtensionManagerDeregisterExtensionResult) GetSuccess() *ExtensionStatus {\n\tif !p.IsSetSuccess() {\n\t\treturn ExtensionManagerDeregisterExtensionResult_Success_DEFAULT\n\t}\n\treturn p.Success\n}\nfunc (p *ExtensionManagerDeregisterExtensionResult) IsSetSuccess() bool {\n\treturn p.Success != nil\n}\n\nfunc (p *ExtensionManagerDeregisterExtensionResult) Read(ctx context.Context, iprot thrift.TProtocol) error {\n\tif _, err := iprot.ReadStructBegin(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T read error: \", p), err)\n\t}\n\n\tfor {\n\t\t_, fieldTypeId, fieldId, err := iprot.ReadFieldBegin(ctx)\n\t\tif err != nil {\n\t\t\treturn thrift.PrependError(fmt.Sprintf(\"%T field %d read error: \", p, fieldId), err)\n\t\t}\n\t\tif fieldTypeId == thrift.STOP {\n\t\t\tbreak\n\t\t}\n\t\tswitch fieldId {\n\t\tcase 0:\n\t\t\tif fieldTypeId == thrift.STRUCT {\n\t\t\t\tif err := p.ReadField0(ctx, iprot); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := iprot.Skip(ctx, fieldTypeId); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tif err := iprot.Skip(ctx, fieldTypeId); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\tif err := iprot.ReadFieldEnd(ctx); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif err := iprot.ReadStructEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T read struct end error: \", p), err)\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionManagerDeregisterExtensionResult) ReadField0(ctx context.Context, iprot thrift.TProtocol) error {\n\tp.Success = &ExtensionStatus{}\n\tif err := p.Success.Read(ctx, iprot); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T error reading struct: \", p.Success), err)\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionManagerDeregisterExtensionResult) Write(ctx context.Context, oprot thrift.TProtocol) error {\n\tif err := oprot.WriteStructBegin(ctx, \"deregisterExtension_result\"); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write struct begin error: \", p), err)\n\t}\n\tif p != nil {\n\t\tif err := p.writeField0(ctx, oprot); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif err := oprot.WriteFieldStop(ctx); err != nil {\n\t\treturn thrift.PrependError(\"write field stop error: \", err)\n\t}\n\tif err := oprot.WriteStructEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(\"write struct stop error: \", err)\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionManagerDeregisterExtensionResult) writeField0(ctx context.Context, oprot thrift.TProtocol) (err error) {\n\tif p.IsSetSuccess() {\n\t\tif err := oprot.WriteFieldBegin(ctx, \"success\", thrift.STRUCT, 0); err != nil {\n\t\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write field begin error 0:success: \", p), err)\n\t\t}\n\t\tif err := p.Success.Write(ctx, oprot); err != nil {\n\t\t\treturn thrift.PrependError(fmt.Sprintf(\"%T error writing struct: \", p.Success), err)\n\t\t}\n\t\tif err := oprot.WriteFieldEnd(ctx); err != nil {\n\t\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write field end error 0:success: \", p), err)\n\t\t}\n\t}\n\treturn err\n}\n\nfunc (p *ExtensionManagerDeregisterExtensionResult) String() string {\n\tif p == nil {\n\t\treturn \"<nil>\"\n\t}\n\treturn fmt.Sprintf(\"ExtensionManagerDeregisterExtensionResult(%+v)\", *p)\n}\n\n// Attributes:\n//  - Sql\ntype ExtensionManagerQueryArgs struct {\n\tSql string `thrift:\"sql,1\" db:\"sql\" json:\"sql\"`\n}\n\nfunc NewExtensionManagerQueryArgs() *ExtensionManagerQueryArgs {\n\treturn &ExtensionManagerQueryArgs{}\n}\n\nfunc (p *ExtensionManagerQueryArgs) GetSql() string {\n\treturn p.Sql\n}\nfunc (p *ExtensionManagerQueryArgs) Read(ctx context.Context, iprot thrift.TProtocol) error {\n\tif _, err := iprot.ReadStructBegin(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T read error: \", p), err)\n\t}\n\n\tfor {\n\t\t_, fieldTypeId, fieldId, err := iprot.ReadFieldBegin(ctx)\n\t\tif err != nil {\n\t\t\treturn thrift.PrependError(fmt.Sprintf(\"%T field %d read error: \", p, fieldId), err)\n\t\t}\n\t\tif fieldTypeId == thrift.STOP {\n\t\t\tbreak\n\t\t}\n\t\tswitch fieldId {\n\t\tcase 1:\n\t\t\tif fieldTypeId == thrift.STRING {\n\t\t\t\tif err := p.ReadField1(ctx, iprot); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := iprot.Skip(ctx, fieldTypeId); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tif err := iprot.Skip(ctx, fieldTypeId); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\tif err := iprot.ReadFieldEnd(ctx); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif err := iprot.ReadStructEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T read struct end error: \", p), err)\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionManagerQueryArgs) ReadField1(ctx context.Context, iprot thrift.TProtocol) error {\n\tif v, err := iprot.ReadString(ctx); err != nil {\n\t\treturn thrift.PrependError(\"error reading field 1: \", err)\n\t} else {\n\t\tp.Sql = v\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionManagerQueryArgs) Write(ctx context.Context, oprot thrift.TProtocol) error {\n\tif err := oprot.WriteStructBegin(ctx, \"query_args\"); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write struct begin error: \", p), err)\n\t}\n\tif p != nil {\n\t\tif err := p.writeField1(ctx, oprot); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif err := oprot.WriteFieldStop(ctx); err != nil {\n\t\treturn thrift.PrependError(\"write field stop error: \", err)\n\t}\n\tif err := oprot.WriteStructEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(\"write struct stop error: \", err)\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionManagerQueryArgs) writeField1(ctx context.Context, oprot thrift.TProtocol) (err error) {\n\tif err := oprot.WriteFieldBegin(ctx, \"sql\", thrift.STRING, 1); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write field begin error 1:sql: \", p), err)\n\t}\n\tif err := oprot.WriteString(ctx, string(p.Sql)); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T.sql (1) field write error: \", p), err)\n\t}\n\tif err := oprot.WriteFieldEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write field end error 1:sql: \", p), err)\n\t}\n\treturn err\n}\n\nfunc (p *ExtensionManagerQueryArgs) String() string {\n\tif p == nil {\n\t\treturn \"<nil>\"\n\t}\n\treturn fmt.Sprintf(\"ExtensionManagerQueryArgs(%+v)\", *p)\n}\n\n// Attributes:\n//  - Success\ntype ExtensionManagerQueryResult struct {\n\tSuccess *ExtensionResponse `thrift:\"success,0\" db:\"success\" json:\"success,omitempty\"`\n}\n\nfunc NewExtensionManagerQueryResult() *ExtensionManagerQueryResult {\n\treturn &ExtensionManagerQueryResult{}\n}\n\nvar ExtensionManagerQueryResult_Success_DEFAULT *ExtensionResponse\n\nfunc (p *ExtensionManagerQueryResult) GetSuccess() *ExtensionResponse {\n\tif !p.IsSetSuccess() {\n\t\treturn ExtensionManagerQueryResult_Success_DEFAULT\n\t}\n\treturn p.Success\n}\nfunc (p *ExtensionManagerQueryResult) IsSetSuccess() bool {\n\treturn p.Success != nil\n}\n\nfunc (p *ExtensionManagerQueryResult) Read(ctx context.Context, iprot thrift.TProtocol) error {\n\tif _, err := iprot.ReadStructBegin(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T read error: \", p), err)\n\t}\n\n\tfor {\n\t\t_, fieldTypeId, fieldId, err := iprot.ReadFieldBegin(ctx)\n\t\tif err != nil {\n\t\t\treturn thrift.PrependError(fmt.Sprintf(\"%T field %d read error: \", p, fieldId), err)\n\t\t}\n\t\tif fieldTypeId == thrift.STOP {\n\t\t\tbreak\n\t\t}\n\t\tswitch fieldId {\n\t\tcase 0:\n\t\t\tif fieldTypeId == thrift.STRUCT {\n\t\t\t\tif err := p.ReadField0(ctx, iprot); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := iprot.Skip(ctx, fieldTypeId); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tif err := iprot.Skip(ctx, fieldTypeId); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\tif err := iprot.ReadFieldEnd(ctx); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif err := iprot.ReadStructEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T read struct end error: \", p), err)\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionManagerQueryResult) ReadField0(ctx context.Context, iprot thrift.TProtocol) error {\n\tp.Success = &ExtensionResponse{}\n\tif err := p.Success.Read(ctx, iprot); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T error reading struct: \", p.Success), err)\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionManagerQueryResult) Write(ctx context.Context, oprot thrift.TProtocol) error {\n\tif err := oprot.WriteStructBegin(ctx, \"query_result\"); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write struct begin error: \", p), err)\n\t}\n\tif p != nil {\n\t\tif err := p.writeField0(ctx, oprot); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif err := oprot.WriteFieldStop(ctx); err != nil {\n\t\treturn thrift.PrependError(\"write field stop error: \", err)\n\t}\n\tif err := oprot.WriteStructEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(\"write struct stop error: \", err)\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionManagerQueryResult) writeField0(ctx context.Context, oprot thrift.TProtocol) (err error) {\n\tif p.IsSetSuccess() {\n\t\tif err := oprot.WriteFieldBegin(ctx, \"success\", thrift.STRUCT, 0); err != nil {\n\t\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write field begin error 0:success: \", p), err)\n\t\t}\n\t\tif err := p.Success.Write(ctx, oprot); err != nil {\n\t\t\treturn thrift.PrependError(fmt.Sprintf(\"%T error writing struct: \", p.Success), err)\n\t\t}\n\t\tif err := oprot.WriteFieldEnd(ctx); err != nil {\n\t\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write field end error 0:success: \", p), err)\n\t\t}\n\t}\n\treturn err\n}\n\nfunc (p *ExtensionManagerQueryResult) String() string {\n\tif p == nil {\n\t\treturn \"<nil>\"\n\t}\n\treturn fmt.Sprintf(\"ExtensionManagerQueryResult(%+v)\", *p)\n}\n\n// Attributes:\n//  - Sql\ntype ExtensionManagerGetQueryColumnsArgs struct {\n\tSql string `thrift:\"sql,1\" db:\"sql\" json:\"sql\"`\n}\n\nfunc NewExtensionManagerGetQueryColumnsArgs() *ExtensionManagerGetQueryColumnsArgs {\n\treturn &ExtensionManagerGetQueryColumnsArgs{}\n}\n\nfunc (p *ExtensionManagerGetQueryColumnsArgs) GetSql() string {\n\treturn p.Sql\n}\nfunc (p *ExtensionManagerGetQueryColumnsArgs) Read(ctx context.Context, iprot thrift.TProtocol) error {\n\tif _, err := iprot.ReadStructBegin(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T read error: \", p), err)\n\t}\n\n\tfor {\n\t\t_, fieldTypeId, fieldId, err := iprot.ReadFieldBegin(ctx)\n\t\tif err != nil {\n\t\t\treturn thrift.PrependError(fmt.Sprintf(\"%T field %d read error: \", p, fieldId), err)\n\t\t}\n\t\tif fieldTypeId == thrift.STOP {\n\t\t\tbreak\n\t\t}\n\t\tswitch fieldId {\n\t\tcase 1:\n\t\t\tif fieldTypeId == thrift.STRING {\n\t\t\t\tif err := p.ReadField1(ctx, iprot); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := iprot.Skip(ctx, fieldTypeId); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tif err := iprot.Skip(ctx, fieldTypeId); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\tif err := iprot.ReadFieldEnd(ctx); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif err := iprot.ReadStructEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T read struct end error: \", p), err)\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionManagerGetQueryColumnsArgs) ReadField1(ctx context.Context, iprot thrift.TProtocol) error {\n\tif v, err := iprot.ReadString(ctx); err != nil {\n\t\treturn thrift.PrependError(\"error reading field 1: \", err)\n\t} else {\n\t\tp.Sql = v\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionManagerGetQueryColumnsArgs) Write(ctx context.Context, oprot thrift.TProtocol) error {\n\tif err := oprot.WriteStructBegin(ctx, \"getQueryColumns_args\"); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write struct begin error: \", p), err)\n\t}\n\tif p != nil {\n\t\tif err := p.writeField1(ctx, oprot); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif err := oprot.WriteFieldStop(ctx); err != nil {\n\t\treturn thrift.PrependError(\"write field stop error: \", err)\n\t}\n\tif err := oprot.WriteStructEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(\"write struct stop error: \", err)\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionManagerGetQueryColumnsArgs) writeField1(ctx context.Context, oprot thrift.TProtocol) (err error) {\n\tif err := oprot.WriteFieldBegin(ctx, \"sql\", thrift.STRING, 1); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write field begin error 1:sql: \", p), err)\n\t}\n\tif err := oprot.WriteString(ctx, string(p.Sql)); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T.sql (1) field write error: \", p), err)\n\t}\n\tif err := oprot.WriteFieldEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write field end error 1:sql: \", p), err)\n\t}\n\treturn err\n}\n\nfunc (p *ExtensionManagerGetQueryColumnsArgs) String() string {\n\tif p == nil {\n\t\treturn \"<nil>\"\n\t}\n\treturn fmt.Sprintf(\"ExtensionManagerGetQueryColumnsArgs(%+v)\", *p)\n}\n\n// Attributes:\n//  - Success\ntype ExtensionManagerGetQueryColumnsResult struct {\n\tSuccess *ExtensionResponse `thrift:\"success,0\" db:\"success\" json:\"success,omitempty\"`\n}\n\nfunc NewExtensionManagerGetQueryColumnsResult() *ExtensionManagerGetQueryColumnsResult {\n\treturn &ExtensionManagerGetQueryColumnsResult{}\n}\n\nvar ExtensionManagerGetQueryColumnsResult_Success_DEFAULT *ExtensionResponse\n\nfunc (p *ExtensionManagerGetQueryColumnsResult) GetSuccess() *ExtensionResponse {\n\tif !p.IsSetSuccess() {\n\t\treturn ExtensionManagerGetQueryColumnsResult_Success_DEFAULT\n\t}\n\treturn p.Success\n}\nfunc (p *ExtensionManagerGetQueryColumnsResult) IsSetSuccess() bool {\n\treturn p.Success != nil\n}\n\nfunc (p *ExtensionManagerGetQueryColumnsResult) Read(ctx context.Context, iprot thrift.TProtocol) error {\n\tif _, err := iprot.ReadStructBegin(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T read error: \", p), err)\n\t}\n\n\tfor {\n\t\t_, fieldTypeId, fieldId, err := iprot.ReadFieldBegin(ctx)\n\t\tif err != nil {\n\t\t\treturn thrift.PrependError(fmt.Sprintf(\"%T field %d read error: \", p, fieldId), err)\n\t\t}\n\t\tif fieldTypeId == thrift.STOP {\n\t\t\tbreak\n\t\t}\n\t\tswitch fieldId {\n\t\tcase 0:\n\t\t\tif fieldTypeId == thrift.STRUCT {\n\t\t\t\tif err := p.ReadField0(ctx, iprot); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := iprot.Skip(ctx, fieldTypeId); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tif err := iprot.Skip(ctx, fieldTypeId); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\tif err := iprot.ReadFieldEnd(ctx); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif err := iprot.ReadStructEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T read struct end error: \", p), err)\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionManagerGetQueryColumnsResult) ReadField0(ctx context.Context, iprot thrift.TProtocol) error {\n\tp.Success = &ExtensionResponse{}\n\tif err := p.Success.Read(ctx, iprot); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T error reading struct: \", p.Success), err)\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionManagerGetQueryColumnsResult) Write(ctx context.Context, oprot thrift.TProtocol) error {\n\tif err := oprot.WriteStructBegin(ctx, \"getQueryColumns_result\"); err != nil {\n\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write struct begin error: \", p), err)\n\t}\n\tif p != nil {\n\t\tif err := p.writeField0(ctx, oprot); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif err := oprot.WriteFieldStop(ctx); err != nil {\n\t\treturn thrift.PrependError(\"write field stop error: \", err)\n\t}\n\tif err := oprot.WriteStructEnd(ctx); err != nil {\n\t\treturn thrift.PrependError(\"write struct stop error: \", err)\n\t}\n\treturn nil\n}\n\nfunc (p *ExtensionManagerGetQueryColumnsResult) writeField0(ctx context.Context, oprot thrift.TProtocol) (err error) {\n\tif p.IsSetSuccess() {\n\t\tif err := oprot.WriteFieldBegin(ctx, \"success\", thrift.STRUCT, 0); err != nil {\n\t\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write field begin error 0:success: \", p), err)\n\t\t}\n\t\tif err := p.Success.Write(ctx, oprot); err != nil {\n\t\t\treturn thrift.PrependError(fmt.Sprintf(\"%T error writing struct: \", p.Success), err)\n\t\t}\n\t\tif err := oprot.WriteFieldEnd(ctx); err != nil {\n\t\t\treturn thrift.PrependError(fmt.Sprintf(\"%T write field end error 0:success: \", p), err)\n\t\t}\n\t}\n\treturn err\n}\n\nfunc (p *ExtensionManagerGetQueryColumnsResult) String() string {\n\tif p == nil {\n\t\treturn \"<nil>\"\n\t}\n\treturn fmt.Sprintf(\"ExtensionManagerGetQueryColumnsResult(%+v)\", *p)\n}\n"
  },
  {
    "path": "go.mod",
    "content": "module github.com/osquery/osquery-go\n\nrequire (\n\tgithub.com/Microsoft/go-winio v0.6.2\n\tgithub.com/apache/thrift v0.20.0\n\tgithub.com/pkg/errors v0.8.0\n\tgithub.com/stretchr/testify v1.8.3\n\tgo.opentelemetry.io/otel v1.16.0\n\tgo.opentelemetry.io/otel/trace v1.16.0\n)\n\nrequire (\n\tgithub.com/davecgh/go-spew v1.1.1 // indirect\n\tgithub.com/go-logr/logr v1.2.4 // indirect\n\tgithub.com/go-logr/stdr v1.2.2 // indirect\n\tgithub.com/pmezard/go-difflib v1.0.0 // indirect\n\tgo.opentelemetry.io/otel/metric v1.16.0 // indirect\n\tgolang.org/x/sys v0.25.0 // indirect\n\tgopkg.in/yaml.v3 v3.0.1 // indirect\n)\n\ngo 1.26\n"
  },
  {
    "path": "go.sum",
    "content": "github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=\ngithub.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=\ngithub.com/apache/thrift v0.20.0 h1:631+KvYbsBZxmuJjYwhezVsrfc/TbqtZV4QcxOX1fOI=\ngithub.com/apache/thrift v0.20.0/go.mod h1:hOk1BQqcp2OLzGsyVXdfMk7YFlMxK3aoEVhjD06QhB8=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=\ngithub.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=\ngithub.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=\ngithub.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=\ngithub.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=\ngithub.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=\ngithub.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=\ngithub.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=\ngithub.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=\ngithub.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=\ngo.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s=\ngo.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4=\ngo.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo=\ngo.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4=\ngo.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs=\ngo.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0=\ngolang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=\ngolang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\n"
  },
  {
    "path": "locker.go",
    "content": "package osquery\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"time\"\n)\n\n// locker uses go channels to create a lock mechanism. We use channels, and not the more common mutexes, because the\n// latter cannot be interrupted. This allows callers to timeout without blocking on the mutex.\n//\n// We need _some_ lock mechanism because the underlying thrift socket only allows a single actor at a time. If two\n// goroutines are trying to use the socket at the same time, they will get protocol errors.\ntype locker struct {\n\tc              chan struct{}\n\tdefaultTimeout time.Duration // Default wait time is used if context does not have a deadline\n\tmaxWait        time.Duration // Maximum time something is allowed to wait\n}\n\nfunc NewLocker(defaultTimeout time.Duration, maxWait time.Duration) *locker {\n\treturn &locker{\n\t\tc:              make(chan struct{}, 1),\n\t\tdefaultTimeout: defaultTimeout,\n\t\tmaxWait:        maxWait,\n\t}\n}\n\n// Lock attempts to lock l. It will wait for the shorter of (ctx deadline | defaultTimeout) and maxWait.\nfunc (l *locker) Lock(ctx context.Context) error {\n\t// Assume most callers have set a deadline on the context, and start this as being the max allowed wait time\n\twait := l.maxWait\n\ttimeoutError := \"timeout after maximum of %s\"\n\n\t// If the caller has not set a deadline, use the default.\n\tif _, ok := ctx.Deadline(); !ok {\n\t\twait = l.defaultTimeout\n\t\ttimeoutError = \"timeout after %s\"\n\n\t}\n\n\ttimeout := time.NewTimer(wait)\n\tdefer timeout.Stop()\n\n\t// Block until we get the lock, the context is canceled, or we time out.\n\tselect {\n\tcase l.c <- struct{}{}:\n\t\t// lock acquired\n\t\treturn nil\n\tcase <-ctx.Done():\n\t\t// context has been canceled\n\t\treturn fmt.Errorf(\"context canceled: %w\", ctx.Err())\n\tcase <-timeout.C:\n\t\t// timed out\n\t\treturn fmt.Errorf(timeoutError, wait)\n\t}\n}\n\n// Unlock unlocks l. It is a runtime error to unlock an unlocked locker.\nfunc (l *locker) Unlock() {\n\tselect {\n\tcase <-l.c:\n\t\treturn\n\tdefault:\n\t\t// Calling Unlock on an unlocked mutex is a fatal error. We mirror that behavior here.\n\t\tpanic(\"unlock of unlocked locker\")\n\t}\n\n}\n"
  },
  {
    "path": "locker_test.go",
    "content": "package osquery\n\nimport (\n\t\"context\"\n\t\"math/rand\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestLocker(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tname                   string\n\t\tsleepTime              time.Duration\n\t\tctxTimeout             time.Duration\n\t\tparallelism            int\n\t\texpectedSuccessesRange [2]int\n\t\texpectedErrorRange     [2]int\n\t\texpectedErrors         []string\n\t}{\n\t\t{\n\t\t\tname:                   \"basic\",\n\t\t\tsleepTime:              1 * time.Millisecond,\n\t\t\tctxTimeout:             10 * time.Millisecond,\n\t\t\tparallelism:            5,\n\t\t\texpectedSuccessesRange: [2]int{5, 5},\n\t\t},\n\t\t{\n\t\t\tname:                   \"some finishers\",\n\t\t\tsleepTime:              4 * time.Millisecond,\n\t\t\tctxTimeout:             10 * time.Millisecond,\n\t\t\tparallelism:            5,\n\t\t\texpectedSuccessesRange: [2]int{2, 3},\n\t\t\texpectedErrorRange:     [2]int{2, 3},\n\t\t},\n\t\t{\n\t\t\tname:                   \"sleep longer than context\",\n\t\t\tsleepTime:              150 * time.Millisecond,\n\t\t\tctxTimeout:             10 * time.Millisecond,\n\t\t\tparallelism:            5,\n\t\t\texpectedSuccessesRange: [2]int{1, 1},\n\t\t\texpectedErrorRange:     [2]int{4, 4},\n\t\t\texpectedErrors:         []string{\"context canceled: context deadline exceeded\"},\n\t\t},\n\t\t{\n\t\t\tname:                   \"no ctx fall back to default timeout\",\n\t\t\tsleepTime:              150 * time.Millisecond,\n\t\t\tparallelism:            5,\n\t\t\texpectedSuccessesRange: [2]int{1, 1},\n\t\t\texpectedErrorRange:     [2]int{4, 4},\n\t\t\texpectedErrors:         []string{\"timeout after 100ms\"},\n\t\t},\n\t\t{\n\t\t\tname:                   \"ctx longer than maxwait\",\n\t\t\tsleepTime:              250 * time.Millisecond,\n\t\t\tctxTimeout:             10 * time.Second,\n\t\t\tparallelism:            5,\n\t\t\texpectedSuccessesRange: [2]int{1, 1},\n\t\t\texpectedErrorRange:     [2]int{4, 4},\n\t\t\texpectedErrors:         []string{\"timeout after maximum of 200ms\"},\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\ttt := tt\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tdoer := NewThingDoer()\n\n\t\t\twait := sync.WaitGroup{}\n\t\t\tfor i := 0; i < tt.parallelism; i++ {\n\t\t\t\twait.Add(1)\n\t\t\t\tgo func() {\n\t\t\t\t\tdefer wait.Done()\n\n\t\t\t\t\tctx := context.TODO()\n\t\t\t\t\tif tt.ctxTimeout != 0 {\n\t\t\t\t\t\tvar cancel context.CancelFunc\n\t\t\t\t\t\tctx, cancel = context.WithTimeout(ctx, tt.ctxTimeout)\n\t\t\t\t\t\tdefer cancel()\n\t\t\t\t\t}\n\n\t\t\t\t\t_ = doer.Once(ctx, tt.sleepTime)\n\t\t\t\t}()\n\t\t\t}\n\n\t\t\twait.Wait()\n\n\t\t\tassertBetween(t, doer.Successes, tt.expectedSuccessesRange, \"success count\")\n\t\t\tassertBetween(t, len(doer.Errors), tt.expectedErrorRange, \"error count\")\n\n\t\t\tfor _, errMsg := range tt.expectedErrors {\n\t\t\t\tassert.Contains(t, doer.Errors, errMsg)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestNeedlessUnlock(t *testing.T) {\n\tt.Parallel()\n\n\tlocker := NewLocker(100*time.Millisecond, 200*time.Millisecond)\n\tassert.Panics(t, func() { locker.Unlock() })\n}\n\nfunc TestDoubleUnlock(t *testing.T) {\n\tt.Parallel()\n\n\tlocker := NewLocker(100*time.Millisecond, 200*time.Millisecond)\n\n\trequire.NoError(t, locker.Lock(context.TODO()))\n\tassert.NotPanics(t, func() { locker.Unlock() })\n\tassert.Panics(t, func() { locker.Unlock() })\n}\n\nfunc TestLockerChaos(t *testing.T) {\n\tt.Parallel()\n\n\tdoer := NewThingDoer()\n\n\twait := sync.WaitGroup{}\n\tfor i := 0; i < 100; i++ {\n\t\twait.Add(1)\n\t\tgo func() {\n\t\t\tdefer wait.Done()\n\n\t\t\tctx := context.TODO()\n\t\t\tif rand.Intn(100) > 20 {\n\t\t\t\tvar cancel context.CancelFunc\n\t\t\t\tctx, cancel = context.WithTimeout(ctx, time.Duration(rand.Intn(500))*time.Millisecond)\n\t\t\t\tdefer cancel()\n\t\t\t}\n\n\t\t\t_ = doer.Once(ctx, time.Duration(rand.Intn(100))*time.Millisecond)\n\t\t}()\n\t}\n\twait.Wait()\n\n\tassert.GreaterOrEqual(t, doer.Successes, 1, \"successes\")\n\tassert.GreaterOrEqual(t, len(doer.Errors), 1, \"failures\")\n\n}\n\ntype thingDoer struct {\n\tlocker    *locker\n\tSuccesses int\n\tErrors    []string\n\terrMu     sync.Mutex\n}\n\nfunc NewThingDoer() *thingDoer {\n\treturn &thingDoer{\n\t\tlocker: NewLocker(100*time.Millisecond, 200*time.Millisecond),\n\t\tErrors: make([]string, 0),\n\t}\n}\n\nfunc (doer *thingDoer) Once(ctx context.Context, d time.Duration) error {\n\tif err := doer.locker.Lock(ctx); err != nil {\n\t\tdoer.errMu.Lock()\n\t\tdefer doer.errMu.Unlock()\n\n\t\tdoer.Errors = append(doer.Errors, err.Error())\n\t\treturn err\n\t}\n\tdefer doer.locker.Unlock()\n\n\t// Note that we don't need to protect the success path with a mutext, that is the point of locker\n\ttime.Sleep(d)\n\tdoer.Successes += 1\n\n\treturn nil\n}\n\n// assertBetween is a wrapper over assert.GreateOrEqual and assert.LessOrEqual. We use it to provide small ranges for\n// expected test results. This is because GitHub Actions is prone to weird timing issues and slowdowns\nfunc assertBetween(t *testing.T, actual int, r [2]int, msg string) {\n\tassert.GreaterOrEqual(t, actual, r[0], msg)\n\tassert.LessOrEqual(t, actual, r[1], msg)\n}\n"
  },
  {
    "path": "mock/osquery.go",
    "content": "// Automatically generated by mockimpl. DO NOT EDIT!\n\npackage mock\n\nimport (\n\t\"context\"\n\n\t\"github.com/osquery/osquery-go/gen/osquery\"\n)\n\nvar _ osquery.ExtensionManager = (*ExtensionManager)(nil)\n\ntype CloseFunc func()\n\ntype PingFunc func(ctx context.Context) (*osquery.ExtensionStatus, error)\n\ntype CallFunc func(ctx context.Context, registry string, item string, req osquery.ExtensionPluginRequest) (*osquery.ExtensionResponse, error)\n\ntype ShutdownFunc func(ctx context.Context) error\n\ntype ExtensionsFunc func(ctx context.Context) (osquery.InternalExtensionList, error)\n\ntype RegisterExtensionFunc func(ctx context.Context, info *osquery.InternalExtensionInfo, registry osquery.ExtensionRegistry) (*osquery.ExtensionStatus, error)\n\ntype DeregisterExtensionFunc func(ctx context.Context, uuid osquery.ExtensionRouteUUID) (*osquery.ExtensionStatus, error)\n\ntype OptionsFunc func(ctx context.Context) (osquery.InternalOptionList, error)\n\ntype QueryFunc func(ctx context.Context, sql string) (*osquery.ExtensionResponse, error)\n\ntype GetQueryColumnsFunc func(ctx context.Context, sql string) (*osquery.ExtensionResponse, error)\n\ntype ExtensionManager struct {\n\tCloseFunc        CloseFunc\n\tCloseFuncInvoked bool\n\n\tPingFunc        PingFunc\n\tPingFuncInvoked bool\n\n\tCallFunc        CallFunc\n\tCallFuncInvoked bool\n\n\tShutdownFunc        ShutdownFunc\n\tShutdownFuncInvoked bool\n\n\tExtensionsFunc        ExtensionsFunc\n\tExtensionsFuncInvoked bool\n\n\tRegisterExtensionFunc        RegisterExtensionFunc\n\tRegisterExtensionFuncInvoked bool\n\n\tDeregisterExtensionFunc        DeregisterExtensionFunc\n\tDeregisterExtensionFuncInvoked bool\n\n\tOptionsFunc        OptionsFunc\n\tOptionsFuncInvoked bool\n\n\tQueryFunc        QueryFunc\n\tQueryFuncInvoked bool\n\n\tGetQueryColumnsFunc        GetQueryColumnsFunc\n\tGetQueryColumnsFuncInvoked bool\n}\n\nfunc (m *ExtensionManager) Close() {\n\tm.CloseFuncInvoked = true\n\tm.CloseFunc()\n}\n\nfunc (m *ExtensionManager) Ping(ctx context.Context) (*osquery.ExtensionStatus, error) {\n\tm.PingFuncInvoked = true\n\treturn m.PingFunc(ctx)\n}\n\nfunc (m *ExtensionManager) Call(ctx context.Context, registry string, item string, req osquery.ExtensionPluginRequest) (*osquery.ExtensionResponse, error) {\n\tm.CallFuncInvoked = true\n\treturn m.CallFunc(ctx, registry, item, req)\n}\n\nfunc (m *ExtensionManager) Shutdown(ctx context.Context) error {\n\tm.ShutdownFuncInvoked = true\n\treturn m.ShutdownFunc(ctx)\n}\n\nfunc (m *ExtensionManager) Extensions(ctx context.Context) (osquery.InternalExtensionList, error) {\n\tm.ExtensionsFuncInvoked = true\n\treturn m.ExtensionsFunc(ctx)\n}\n\nfunc (m *ExtensionManager) RegisterExtension(ctx context.Context, info *osquery.InternalExtensionInfo, registry osquery.ExtensionRegistry) (*osquery.ExtensionStatus, error) {\n\tm.RegisterExtensionFuncInvoked = true\n\treturn m.RegisterExtensionFunc(ctx, info, registry)\n}\n\nfunc (m *ExtensionManager) DeregisterExtension(ctx context.Context, uuid osquery.ExtensionRouteUUID) (*osquery.ExtensionStatus, error) {\n\tm.DeregisterExtensionFuncInvoked = true\n\treturn m.DeregisterExtensionFunc(ctx, uuid)\n}\n\nfunc (m *ExtensionManager) Options(ctx context.Context) (osquery.InternalOptionList, error) {\n\tm.OptionsFuncInvoked = true\n\treturn m.OptionsFunc(ctx)\n}\n\nfunc (m *ExtensionManager) Query(ctx context.Context, sql string) (*osquery.ExtensionResponse, error) {\n\tm.QueryFuncInvoked = true\n\treturn m.QueryFunc(ctx, sql)\n}\n\nfunc (m *ExtensionManager) GetQueryColumns(ctx context.Context, sql string) (*osquery.ExtensionResponse, error) {\n\tm.GetQueryColumnsFuncInvoked = true\n\treturn m.GetQueryColumnsFunc(ctx, sql)\n}\n"
  },
  {
    "path": "mock_manager.go",
    "content": "// Automatically generated by mockimpl. DO NOT EDIT!\n\npackage osquery\n\nimport \"github.com/osquery/osquery-go/gen/osquery\"\n\nvar _ ExtensionManager = (*MockExtensionManager)(nil)\n\ntype CloseFunc func()\n\ntype PingFunc func() (*osquery.ExtensionStatus, error)\n\ntype CallFunc func(registry string, item string, req osquery.ExtensionPluginRequest) (*osquery.ExtensionResponse, error)\n\ntype ExtensionsFunc func() (osquery.InternalExtensionList, error)\n\ntype RegisterExtensionFunc func(info *osquery.InternalExtensionInfo, registry osquery.ExtensionRegistry) (*osquery.ExtensionStatus, error)\n\ntype DeregisterExtensionFunc func(uuid osquery.ExtensionRouteUUID) (*osquery.ExtensionStatus, error)\n\ntype OptionsFunc func() (osquery.InternalOptionList, error)\n\ntype QueryFunc func(sql string) (*osquery.ExtensionResponse, error)\n\ntype GetQueryColumnsFunc func(sql string) (*osquery.ExtensionResponse, error)\n\ntype MockExtensionManager struct {\n\tCloseFunc        CloseFunc\n\tCloseFuncInvoked bool\n\n\tPingFunc        PingFunc\n\tPingFuncInvoked bool\n\n\tCallFunc        CallFunc\n\tCallFuncInvoked bool\n\n\tExtensionsFunc        ExtensionsFunc\n\tExtensionsFuncInvoked bool\n\n\tRegisterExtensionFunc        RegisterExtensionFunc\n\tRegisterExtensionFuncInvoked bool\n\n\tDeRegisterExtensionFunc        DeregisterExtensionFunc\n\tDeRegisterExtensionFuncInvoked bool\n\n\tOptionsFunc        OptionsFunc\n\tOptionsFuncInvoked bool\n\n\tQueryFunc        QueryFunc\n\tQueryFuncInvoked bool\n\n\tGetQueryColumnsFunc        GetQueryColumnsFunc\n\tGetQueryColumnsFuncInvoked bool\n}\n\nfunc (m *MockExtensionManager) Close() {\n\tm.CloseFuncInvoked = true\n\tm.CloseFunc()\n}\n\nfunc (m *MockExtensionManager) Ping() (*osquery.ExtensionStatus, error) {\n\tm.PingFuncInvoked = true\n\treturn m.PingFunc()\n}\n\nfunc (m *MockExtensionManager) Call(registry string, item string, req osquery.ExtensionPluginRequest) (*osquery.ExtensionResponse, error) {\n\tm.CallFuncInvoked = true\n\treturn m.CallFunc(registry, item, req)\n}\n\nfunc (m *MockExtensionManager) Extensions() (osquery.InternalExtensionList, error) {\n\tm.ExtensionsFuncInvoked = true\n\treturn m.ExtensionsFunc()\n}\n\nfunc (m *MockExtensionManager) RegisterExtension(info *osquery.InternalExtensionInfo, registry osquery.ExtensionRegistry) (*osquery.ExtensionStatus, error) {\n\tm.RegisterExtensionFuncInvoked = true\n\treturn m.RegisterExtensionFunc(info, registry)\n}\n\nfunc (m *MockExtensionManager) DeregisterExtension(uuid osquery.ExtensionRouteUUID) (*osquery.ExtensionStatus, error) {\n\tm.DeRegisterExtensionFuncInvoked = true\n\treturn m.DeRegisterExtensionFunc(uuid)\n}\n\nfunc (m *MockExtensionManager) Options() (osquery.InternalOptionList, error) {\n\tm.OptionsFuncInvoked = true\n\treturn m.OptionsFunc()\n}\n\nfunc (m *MockExtensionManager) Query(sql string) (*osquery.ExtensionResponse, error) {\n\tm.QueryFuncInvoked = true\n\treturn m.QueryFunc(sql)\n}\n\nfunc (m *MockExtensionManager) GetQueryColumns(sql string) (*osquery.ExtensionResponse, error) {\n\tm.GetQueryColumnsFuncInvoked = true\n\treturn m.GetQueryColumnsFunc(sql)\n}\n"
  },
  {
    "path": "osquery.thrift",
    "content": "namespace cpp osquery.extensions\n\n/// Registry operations use a registry name, plugin name, request/response.\ntypedef map<string, string> ExtensionPluginRequest\ntypedef list<map<string, string>> ExtensionPluginResponse\n\n/// Extensions should request osquery options to set active registries and\n/// bootstrap any config/logger plugins.\nstruct InternalOptionInfo {\n  1:string value,\n  2:string default_value,\n  3:string type,\n}\n\n/// Each option (CLI flag) has a unique name.\ntypedef map<string, InternalOptionInfo> InternalOptionList\n\n/// When communicating extension metadata, use a thrift-internal structure.\nstruct InternalExtensionInfo {\n  1:string name,\n  2:string version,\n  3:string sdk_version,\n  4:string min_sdk_version,\n}\n\n/// Unique ID for each extension.\ntypedef i64 ExtensionRouteUUID\n/// A map from each plugin name to its optional route information.\ntypedef map<string, ExtensionPluginResponse> ExtensionRouteTable\n/// A map from each registry name.\ntypedef map<string, ExtensionRouteTable> ExtensionRegistry\n/// A map from each extension's unique ID to its map of registries.\ntypedef map<ExtensionRouteUUID, InternalExtensionInfo> InternalExtensionList\n\nenum ExtensionCode {\n  EXT_SUCCESS = 0,\n  EXT_FAILED = 1,\n  EXT_FATAL = 2,\n}\n\n/// Most communication uses the Status return type.\nstruct ExtensionStatus {\n  1:i32 code,\n  2:string message,\n  /// Add a thrift Status parameter identifying the request/response.\n  3:ExtensionRouteUUID uuid,\n}\n\nstruct ExtensionResponse {\n  1:ExtensionStatus status,\n  2:ExtensionPluginResponse response,\n}\n\nexception ExtensionException {\n  1:i32 code,\n  2:string message,\n  3:ExtensionRouteUUID uuid,\n}\n\nservice Extension {\n  /// Ping to/from an extension and extension manager for metadata.\n  ExtensionStatus ping(),\n  /// Call an extension (or core) registry plugin.\n  ExtensionResponse call(\n    /// The registry name (e.g., config, logger, table, etc).\n    1:string registry,\n    /// The registry item name (plugin name).\n    2:string item,\n    /// The thrift-equivilent of an osquery::PluginRequest.\n    3:ExtensionPluginRequest request),\n  /// Request that an extension shutdown (does not apply to managers).\n  void shutdown(),\n}\n\n/// The extension manager is run by the osquery core process.\nservice ExtensionManager extends Extension {\n  /// Return the list of active registered extensions.\n  InternalExtensionList extensions(),\n  /// Return the list of bootstrap or configuration options.\n  InternalOptionList options(),\n  /// The API endpoint used by an extension to register its plugins.\n  ExtensionStatus registerExtension(\n    1:InternalExtensionInfo info,\n    2:ExtensionRegistry registry),\n  ExtensionStatus deregisterExtension(\n    1:ExtensionRouteUUID uuid,\n  ),\n  /// Allow an extension to query using an SQL string.\n  ExtensionResponse query(\n    1:string sql,\n  ),\n  /// Allow an extension to introspect into SQL used in a parsed query.\n  ExtensionResponse getQueryColumns(\n    1:string sql,\n  ),\n}\n"
  },
  {
    "path": "plugin/config/config.go",
    "content": "// Package config creates an osquery configuration plugin.\n//\n// See https://osquery.readthedocs.io/en/latest/development/config-plugins/ for more.\npackage config\n\nimport (\n\t\"context\"\n\n\t\"github.com/osquery/osquery-go/gen/osquery\"\n\t\"github.com/osquery/osquery-go/traces\"\n)\n\n// GenerateConfigsFunc returns the configurations generated by this plugin.\n// The returned map should use the source name as key, and the config\n// JSON as values. The context argument can optionally be used for\n// cancellation in long-running operations.\ntype GenerateConfigsFunc func(ctx context.Context) (map[string]string, error)\n\n// Plugin is an osquery configuration plugin. Plugin implements the OsqueryPlugin\n// interface.\ntype Plugin struct {\n\tname     string\n\tgenerate GenerateConfigsFunc\n}\n\n// NewConfigPlugin takes a value that implements ConfigPlugin and wraps it with\n// the appropriate methods to satisfy the OsqueryPlugin interface. Use this to\n// easily create configuration plugins.\nfunc NewPlugin(name string, fn GenerateConfigsFunc) *Plugin {\n\treturn &Plugin{name: name, generate: fn}\n}\n\nfunc (t *Plugin) Name() string {\n\treturn t.name\n}\n\n// Registry name for config plugins\nconst configRegistryName = \"config\"\n\nfunc (t *Plugin) RegistryName() string {\n\treturn configRegistryName\n}\n\nfunc (t *Plugin) Routes() osquery.ExtensionPluginResponse {\n\treturn osquery.ExtensionPluginResponse{}\n}\n\nfunc (t *Plugin) Ping() osquery.ExtensionStatus {\n\treturn osquery.ExtensionStatus{Code: 0, Message: \"OK\"}\n}\n\n// Key that the request method is stored under\nconst requestActionKey = \"action\"\n\n// Action value used when config is requested\nconst genConfigAction = \"genConfig\"\n\nfunc (t *Plugin) Call(ctx context.Context, request osquery.ExtensionPluginRequest) osquery.ExtensionResponse {\n\tctx, span := traces.StartSpan(ctx, \"Config.Call\", \"action\", request[requestActionKey])\n\tdefer span.End()\n\n\tswitch request[requestActionKey] {\n\tcase genConfigAction:\n\t\tconfigs, err := t.generate(ctx)\n\t\tif err != nil {\n\t\t\treturn osquery.ExtensionResponse{\n\t\t\t\tStatus: &osquery.ExtensionStatus{\n\t\t\t\t\tCode:    1,\n\t\t\t\t\tMessage: \"error getting config: \" + err.Error(),\n\t\t\t\t},\n\t\t\t}\n\t\t}\n\n\t\treturn osquery.ExtensionResponse{\n\t\t\tStatus:   &osquery.ExtensionStatus{Code: 0, Message: \"OK\"},\n\t\t\tResponse: osquery.ExtensionPluginResponse{configs},\n\t\t}\n\n\tdefault:\n\t\treturn osquery.ExtensionResponse{\n\t\t\tStatus: &osquery.ExtensionStatus{\n\t\t\t\tCode:    1,\n\t\t\t\tMessage: \"unknown action: \" + request[\"action\"],\n\t\t\t},\n\t\t}\n\t}\n\n}\n\nfunc (t *Plugin) Shutdown() {}\n"
  },
  {
    "path": "plugin/config/config_test.go",
    "content": "package config\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"testing\"\n\n\t\"github.com/osquery/osquery-go/gen/osquery\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nvar StatusOK = osquery.ExtensionStatus{Code: 0, Message: \"OK\"}\n\nfunc TestConfigPlugin(t *testing.T) {\n\tvar called bool\n\tplugin := NewPlugin(\"mock\", func(context.Context) (map[string]string, error) {\n\t\tcalled = true\n\t\treturn map[string]string{\n\t\t\t\"conf1\": \"foobar\",\n\t\t}, nil\n\t})\n\n\t// Basic methods\n\tassert.Equal(t, \"config\", plugin.RegistryName())\n\tassert.Equal(t, \"mock\", plugin.Name())\n\tassert.Equal(t, StatusOK, plugin.Ping())\n\tassert.Equal(t, osquery.ExtensionPluginResponse{}, plugin.Routes())\n\n\t// Call with good action\n\tresp := plugin.Call(context.Background(), osquery.ExtensionPluginRequest{\"action\": \"genConfig\"})\n\tassert.True(t, called)\n\tassert.Equal(t, &StatusOK, resp.Status)\n\tassert.Equal(t, osquery.ExtensionPluginResponse{{\"conf1\": \"foobar\"}}, resp.Response)\n}\n\nfunc TestConfigPluginErrors(t *testing.T) {\n\tvar called bool\n\tplugin := NewPlugin(\"mock\", func(context.Context) (map[string]string, error) {\n\t\tcalled = true\n\t\treturn nil, errors.New(\"foobar\")\n\t})\n\n\t// Call with bad actions\n\tassert.Equal(t, int32(1), plugin.Call(context.Background(), osquery.ExtensionPluginRequest{}).Status.Code)\n\tassert.False(t, called)\n\tassert.Equal(t, int32(1), plugin.Call(context.Background(), osquery.ExtensionPluginRequest{\"action\": \"bad\"}).Status.Code)\n\tassert.False(t, called)\n\n\t// Call with good action but generate fails\n\tresp := plugin.Call(context.Background(), osquery.ExtensionPluginRequest{\"action\": \"genConfig\"})\n\tassert.True(t, called)\n\tassert.Equal(t, int32(1), resp.Status.Code)\n\tassert.Equal(t, \"error getting config: foobar\", resp.Status.Message)\n}\n"
  },
  {
    "path": "plugin/distributed/distributed.go",
    "content": "// Package distributed creates an osquery distributed query plugin.\npackage distributed\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/osquery/osquery-go/gen/osquery\"\n\t\"github.com/osquery/osquery-go/traces\"\n)\n\n// GetQueriesResult contains the information about which queries the\n// distributed system should run.\ntype GetQueriesResult struct {\n\t// Queries is a map from query name to query SQL\n\tQueries map[string]string `json:\"queries\"`\n\t// Discovery is used for \"discovery\" queries in the distributed\n\t// system. When used, discovery queries should be specified with query\n\t// name as the key and the discover query SQL as the value. If this is\n\t// nonempty, only queries for which the associated discovery query\n\t// returns results will be run in osquery.\n\tDiscovery map[string]string `json:\"discovery,omitempty\"`\n\t// AccelerateSeconds can be specified to have \"accelerated\" checkins\n\t// for a given number of seconds after this checkin. Currently this\n\t// means that checkins will occur every 5 seconds.\n\tAccelerateSeconds int `json:\"accelerate,omitempty\"`\n}\n\n// GetQueriesFunc returns the queries that should be executed.\n// The returned map should include the query name as the keys, and the query\n// text as values. Results will be returned corresponding to the provided name.\n// The context argument can optionally be used for cancellation in long-running\n// operations.\ntype GetQueriesFunc func(ctx context.Context) (*GetQueriesResult, error)\n\n// Result contains the status and results for a distributed query.\ntype Result struct {\n\t// QueryName is the name that was originally provided for the query.\n\tQueryName string `json:\"query_name\"`\n\t// Status is an integer status code for the query execution (0 = OK)\n\tStatus int `json:\"status\"`\n\t// Rows is the result rows of the query.\n\tRows []map[string]string `json:\"rows\"`\n\t// QueryStats are the stats about the execution of the given query\n\tQueryStats *Stats `json:\"stats\"`\n\t// Message is the message string indicating the status of the query\n\tMessage string `json:\"message\"`\n}\n\n// WriteResultsFunc writes the results of the executed distributed queries. The\n// query results will be serialized JSON in the results map with the query name\n// as the key.\ntype WriteResultsFunc func(ctx context.Context, results []Result) error\n\n// Plugin is an osquery configuration plugin. Plugin implements the OsqueryPlugin\n// interface.\ntype Plugin struct {\n\tname         string\n\tgetQueries   GetQueriesFunc\n\twriteResults WriteResultsFunc\n}\n\n// NewPlugin takes the distributed query functions and returns a struct\n// implementing the OsqueryPlugin interface. Use this to wrap the appropriate\n// functions into an osquery plugin.\nfunc NewPlugin(name string, getQueries GetQueriesFunc, writeResults WriteResultsFunc) *Plugin {\n\treturn &Plugin{name: name, getQueries: getQueries, writeResults: writeResults}\n}\n\nfunc (t *Plugin) Name() string {\n\treturn t.name\n}\n\n// Registry name for distributed plugins\nconst distributedRegistryName = \"distributed\"\n\nfunc (t *Plugin) RegistryName() string {\n\treturn distributedRegistryName\n}\n\nfunc (t *Plugin) Routes() osquery.ExtensionPluginResponse {\n\treturn osquery.ExtensionPluginResponse{}\n}\n\nfunc (t *Plugin) Ping() osquery.ExtensionStatus {\n\treturn osquery.ExtensionStatus{Code: 0, Message: \"OK\"}\n}\n\n// Key that the request method is stored under\nconst requestActionKey = \"action\"\n\n// Action value used when queries are requested\nconst getQueriesAction = \"getQueries\"\n\n// Action value used when results are written\nconst writeResultsAction = \"writeResults\"\n\n// Key that results are stored under\nconst requestResultKey = \"results\"\n\n// OsqueryInt handles unmarshaling integers in noncanonical osquery json.\ntype OsqueryInt int\n\n// UnmarshalJSON marshals a json string that is convertable to an int, for\n// example \"234\" -> 234.\nfunc (oi *OsqueryInt) UnmarshalJSON(buff []byte) error {\n\ts := string(buff)\n\tif strings.Contains(s, `\"`) {\n\t\tunquoted, err := strconv.Unquote(s)\n\t\tif err != nil {\n\t\t\treturn &json.UnmarshalTypeError{\n\t\t\t\tValue:  string(buff),\n\t\t\t\tType:   reflect.TypeOf(oi),\n\t\t\t\tStruct: \"statuses\",\n\t\t\t}\n\t\t}\n\t\ts = unquoted\n\t}\n\n\tif len(s) == 0 {\n\t\t*oi = OsqueryInt(0)\n\t\treturn nil\n\t}\n\n\tparsedInt, err := strconv.ParseInt(s, 10, 32)\n\tif err != nil {\n\t\treturn &json.UnmarshalTypeError{\n\t\t\tValue:  string(buff),\n\t\t\tType:   reflect.TypeOf(oi),\n\t\t\tStruct: \"statuses\",\n\t\t}\n\t}\n\n\t*oi = OsqueryInt(parsedInt)\n\treturn nil\n}\n\n// ResultsStruct is used for unmarshalling the results passed from osquery.\ntype ResultsStruct struct {\n\tQueries  map[string][]map[string]string `json:\"queries\"`\n\tStatuses map[string]OsqueryInt          `json:\"statuses\"`\n\tStats    map[string]Stats               `json:\"stats\"`\n\tMessages map[string]string              `json:\"messages\"`\n}\n\n// Stats holds performance stats about the execution of a given query.\ntype Stats struct {\n\tWallTimeMs OsqueryInt `json:\"wall_time_ms\"`\n\tUserTime   OsqueryInt `json:\"user_time\"`\n\tSystemTime OsqueryInt `json:\"system_time\"`\n\tMemory     OsqueryInt `json:\"memory\"`\n}\n\n// UnmarshalJSON turns structurally inconsistent osquery json into a ResultsStruct.\nfunc (rs *ResultsStruct) UnmarshalJSON(buff []byte) error {\n\temptyRow := []map[string]string{}\n\trs.Queries = make(map[string][]map[string]string)\n\trs.Statuses = make(map[string]OsqueryInt)\n\trs.Messages = make(map[string]string)\n\t// Queries can be []map[string]string OR an empty string\n\t// so we need to deal with an interface to accommodate two types\n\tintermediate := struct {\n\t\tQueries  map[string]interface{} `json:\"queries\"`\n\t\tStatuses map[string]OsqueryInt  `json:\"statuses\"`\n\t\tStats    map[string]Stats       `json:\"stats\"`\n\t\tMessages map[string]string      `json:\"messages\"`\n\t}{}\n\tif err := json.Unmarshal(buff, &intermediate); err != nil {\n\t\treturn err\n\t}\n\tfor queryName, status := range intermediate.Statuses {\n\t\trs.Statuses[queryName] = status\n\t\t// Sometimes we have a status but don't have a corresponding\n\t\t// result.\n\t\tqueryResult, ok := intermediate.Queries[queryName]\n\t\tif !ok {\n\t\t\trs.Queries[queryName] = emptyRow\n\t\t\tcontinue\n\t\t}\n\t\t// Deal with structurally inconsistent results, sometimes a query\n\t\t// without any results is just a name with an empty string.\n\t\tswitch val := queryResult.(type) {\n\t\tcase string:\n\t\t\trs.Queries[queryName] = emptyRow\n\t\tcase []interface{}:\n\t\t\tresults, err := convertRows(val)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\trs.Queries[queryName] = results\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"results for %q unknown type\", queryName)\n\t\t}\n\t}\n\t// Stats and messages don't require any format changes\n\trs.Stats = intermediate.Stats\n\trs.Messages = intermediate.Messages\n\treturn nil\n}\n\nfunc (rs *ResultsStruct) toResults() ([]Result, error) {\n\tvar results []Result\n\tfor queryName, rows := range rs.Queries {\n\t\tresult := Result{\n\t\t\tQueryName:  queryName,\n\t\t\tRows:       rows,\n\t\t\tStatus:     int(rs.Statuses[queryName]),\n\t\t\tQueryStats: nil,\n\t\t}\n\t\tif stats, ok := rs.Stats[queryName]; ok {\n\t\t\tresult.QueryStats = &stats\n\t\t}\n\t\tif msg, ok := rs.Messages[queryName]; ok {\n\t\t\tresult.Message = msg\n\t\t}\n\t\tresults = append(results, result)\n\t}\n\treturn results, nil\n}\n\nfunc convertRows(rows []interface{}) ([]map[string]string, error) {\n\tvar results []map[string]string\n\tfor _, intf := range rows {\n\t\trow, ok := intf.(map[string]interface{})\n\t\tif !ok {\n\t\t\treturn nil, errors.New(\"invalid row type for query\")\n\t\t}\n\t\tresult := make(map[string]string)\n\t\tfor col, val := range row {\n\t\t\tsval, ok := val.(string)\n\t\t\tif !ok {\n\t\t\t\treturn nil, fmt.Errorf(\"invalid type for col %q\", col)\n\t\t\t}\n\t\t\tresult[col] = sval\n\t\t}\n\t\tresults = append(results, result)\n\t}\n\treturn results, nil\n}\n\nfunc (t *Plugin) Call(ctx context.Context, request osquery.ExtensionPluginRequest) osquery.ExtensionResponse {\n\tctx, span := traces.StartSpan(ctx, \"Distributed.Call\", \"action\", request[requestActionKey])\n\tdefer span.End()\n\n\tswitch request[requestActionKey] {\n\tcase getQueriesAction:\n\t\tqueries, err := t.getQueries(ctx)\n\t\tif err != nil {\n\t\t\treturn osquery.ExtensionResponse{\n\t\t\t\tStatus: &osquery.ExtensionStatus{\n\t\t\t\t\tCode:    1,\n\t\t\t\t\tMessage: \"error getting queries: \" + err.Error(),\n\t\t\t\t},\n\t\t\t}\n\t\t}\n\n\t\tqueryJSON, err := json.Marshal(queries)\n\t\tif err != nil {\n\t\t\treturn osquery.ExtensionResponse{\n\t\t\t\tStatus: &osquery.ExtensionStatus{\n\t\t\t\t\tCode:    1,\n\t\t\t\t\tMessage: \"error marshalling queries: \" + err.Error(),\n\t\t\t\t},\n\t\t\t}\n\t\t}\n\n\t\treturn osquery.ExtensionResponse{\n\t\t\tStatus:   &osquery.ExtensionStatus{Code: 0, Message: \"OK\"},\n\t\t\tResponse: osquery.ExtensionPluginResponse{map[string]string{\"results\": string(queryJSON)}},\n\t\t}\n\n\tcase writeResultsAction:\n\t\tvar rs ResultsStruct\n\t\tif err := json.Unmarshal([]byte(request[requestResultKey]), &rs); err != nil {\n\t\t\treturn osquery.ExtensionResponse{\n\t\t\t\tStatus: &osquery.ExtensionStatus{\n\t\t\t\t\tCode:    1,\n\t\t\t\t\tMessage: \"error unmarshalling results: \" + err.Error(),\n\t\t\t\t},\n\t\t\t}\n\t\t}\n\t\tresults, err := rs.toResults()\n\t\tif err != nil {\n\t\t\treturn osquery.ExtensionResponse{\n\t\t\t\tStatus: &osquery.ExtensionStatus{\n\t\t\t\t\tCode:    1,\n\t\t\t\t\tMessage: \"error writing results: \" + err.Error(),\n\t\t\t\t},\n\t\t\t}\n\t\t}\n\t\t// invoke callback\n\t\terr = t.writeResults(ctx, results)\n\t\tif err != nil {\n\t\t\treturn osquery.ExtensionResponse{\n\t\t\t\tStatus: &osquery.ExtensionStatus{\n\t\t\t\t\tCode:    1,\n\t\t\t\t\tMessage: \"error writing results: \" + err.Error(),\n\t\t\t\t},\n\t\t\t}\n\t\t}\n\n\t\treturn osquery.ExtensionResponse{\n\t\t\tStatus:   &osquery.ExtensionStatus{Code: 0, Message: \"OK\"},\n\t\t\tResponse: osquery.ExtensionPluginResponse{},\n\t\t}\n\n\tdefault:\n\t\treturn osquery.ExtensionResponse{\n\t\t\tStatus: &osquery.ExtensionStatus{\n\t\t\t\tCode:    1,\n\t\t\t\tMessage: \"unknown action: \" + request[\"action\"],\n\t\t\t},\n\t\t}\n\t}\n\n}\n\nfunc (t *Plugin) Shutdown() {}\n"
  },
  {
    "path": "plugin/distributed/distributed_test.go",
    "content": "package distributed\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"sort\"\n\t\"testing\"\n\n\t\"github.com/osquery/osquery-go/gen/osquery\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nvar StatusOK = osquery.ExtensionStatus{Code: 0, Message: \"OK\"}\n\nfunc TestDistributedPlugin(t *testing.T) {\n\tvar getCalled, writeCalled bool\n\tvar results []Result\n\tplugin := NewPlugin(\n\t\t\"mock\",\n\t\tfunc(context.Context) (*GetQueriesResult, error) {\n\t\t\tgetCalled = true\n\t\t\treturn &GetQueriesResult{\n\t\t\t\tQueries: map[string]string{\n\t\t\t\t\t\"query1\": \"select iso_8601 from time\",\n\t\t\t\t\t\"query2\": \"select version from osquery_info\",\n\t\t\t\t\t\"query3\": \"select foo from bar\",\n\t\t\t\t},\n\t\t\t}, nil\n\t\t},\n\t\tfunc(ctx context.Context, res []Result) error {\n\t\t\twriteCalled = true\n\t\t\tresults = res\n\t\t\treturn nil\n\t\t},\n\t)\n\n\t// Basic methods\n\tassert.Equal(t, \"distributed\", plugin.RegistryName())\n\tassert.Equal(t, \"mock\", plugin.Name())\n\tassert.Equal(t, StatusOK, plugin.Ping())\n\tassert.Equal(t, osquery.ExtensionPluginResponse{}, plugin.Routes())\n\n\t// Call getQueries\n\tresp := plugin.Call(context.Background(), osquery.ExtensionPluginRequest{\"action\": \"getQueries\"})\n\tassert.True(t, getCalled)\n\tassert.False(t, writeCalled)\n\tassert.Equal(t, &StatusOK, resp.Status)\n\tif assert.Len(t, resp.Response, 1) {\n\t\tassert.JSONEq(t, `{\"queries\": {\"query1\": \"select iso_8601 from time\", \"query2\": \"select version from osquery_info\", \"query3\": \"select foo from bar\"}}`,\n\t\t\tresp.Response[0][\"results\"])\n\t}\n\n\t// Call writeResults\n\tgetCalled = false\n\tresp = plugin.Call(context.Background(), osquery.ExtensionPluginRequest{\"action\": \"writeResults\", \"results\": `{\"queries\":{\"query1\":[{\"iso_8601\":\"2017-07-10T22:08:40Z\"}],\"query2\":[{\"version\":\"2.4.0\"}]},\"statuses\":{\"query1\":\"0\",\"query2\":\"0\",\"query3\":\"1\"}, \"stats\":{\"query1\":{\"wall_time_ms\": 1, \"user_time\": 1, \"system_time\": 1, \"memory\": 1},\"query2\":{\"wall_time_ms\": 2, \"user_time\": 2, \"system_time\": 2, \"memory\": 2},\"query3\":{\"wall_time_ms\": 3, \"user_time\": 3, \"system_time\": 3, \"memory\": 3}}}`})\n\tassert.False(t, getCalled)\n\tassert.True(t, writeCalled)\n\tassert.Equal(t, &StatusOK, resp.Status)\n\t// Ensure correct ordering for comparison\n\tsort.Slice(results, func(i, j int) bool { return results[i].QueryName < results[j].QueryName })\n\tassert.Equal(t, []Result{\n\t\t{\"query1\", 0, []map[string]string{{\"iso_8601\": \"2017-07-10T22:08:40Z\"}}, &Stats{WallTimeMs: 1, UserTime: 1, SystemTime: 1, Memory: 1}, \"\"},\n\t\t{\"query2\", 0, []map[string]string{{\"version\": \"2.4.0\"}}, &Stats{WallTimeMs: 2, UserTime: 2, SystemTime: 2, Memory: 2}, \"\"},\n\t\t{\"query3\", 1, []map[string]string{}, &Stats{WallTimeMs: 3, UserTime: 3, SystemTime: 3, Memory: 3}, \"\"},\n\t},\n\t\tresults)\n\n\t// Call writeResults -- no stats attached\n\tgetCalled = false\n\tresp = plugin.Call(context.Background(), osquery.ExtensionPluginRequest{\"action\": \"writeResults\", \"results\": `{\"queries\":{\"query1\":[{\"iso_8601\":\"2017-07-10T22:08:40Z\"}],\"query2\":[{\"version\":\"2.4.0\"}]},\"statuses\":{\"query1\":\"0\",\"query2\":\"0\",\"query3\":\"1\"}}`})\n\tassert.False(t, getCalled)\n\tassert.True(t, writeCalled)\n\tassert.Equal(t, &StatusOK, resp.Status)\n\t// Ensure correct ordering for comparison\n\tsort.Slice(results, func(i, j int) bool { return results[i].QueryName < results[j].QueryName })\n\tassert.Equal(t, []Result{\n\t\t{\"query1\", 0, []map[string]string{{\"iso_8601\": \"2017-07-10T22:08:40Z\"}}, nil, \"\"},\n\t\t{\"query2\", 0, []map[string]string{{\"version\": \"2.4.0\"}}, nil, \"\"},\n\t\t{\"query3\", 1, []map[string]string{}, nil, \"\"},\n\t},\n\t\tresults)\n\n\t// Call writeResults -- with message included\n\tgetCalled = false\n\tresp = plugin.Call(context.Background(), osquery.ExtensionPluginRequest{\"action\": \"writeResults\", \"results\": `{\"queries\":{\"query1\":[{\"iso_8601\":\"2017-07-10T22:08:40Z\"}],\"query2\":[{\"version\":\"2.4.0\"}]},\"statuses\":{\"query1\":\"0\",\"query2\":\"0\",\"query3\":\"1\"}, \"stats\":{\"query1\":{\"wall_time_ms\": 1, \"user_time\": 1, \"system_time\": 1, \"memory\": 1},\"query2\":{\"wall_time_ms\": 2, \"user_time\": 2, \"system_time\": 2, \"memory\": 2},\"query3\":{\"wall_time_ms\": 3, \"user_time\": 3, \"system_time\": 3, \"memory\": 3}}, \"messages\": {\"query3\": \"distributed query is denylisted\"}}`})\n\tassert.False(t, getCalled)\n\tassert.True(t, writeCalled)\n\tassert.Equal(t, &StatusOK, resp.Status)\n\t// Ensure correct ordering for comparison\n\tsort.Slice(results, func(i, j int) bool { return results[i].QueryName < results[j].QueryName })\n\tassert.Equal(t, []Result{\n\t\t{\"query1\", 0, []map[string]string{{\"iso_8601\": \"2017-07-10T22:08:40Z\"}}, &Stats{WallTimeMs: 1, UserTime: 1, SystemTime: 1, Memory: 1}, \"\"},\n\t\t{\"query2\", 0, []map[string]string{{\"version\": \"2.4.0\"}}, &Stats{WallTimeMs: 2, UserTime: 2, SystemTime: 2, Memory: 2}, \"\"},\n\t\t{\"query3\", 1, []map[string]string{}, &Stats{WallTimeMs: 3, UserTime: 3, SystemTime: 3, Memory: 3}, \"distributed query is denylisted\"},\n\t},\n\t\tresults)\n}\n\nfunc TestDistributedPluginAccelerateDiscovery(t *testing.T) {\n\tplugin := NewPlugin(\n\t\t\"mock\",\n\t\tfunc(context.Context) (*GetQueriesResult, error) {\n\t\t\treturn &GetQueriesResult{\n\t\t\t\tQueries: map[string]string{\n\t\t\t\t\t\"query1\": \"select * from time\",\n\t\t\t\t},\n\t\t\t\tDiscovery: map[string]string{\n\t\t\t\t\t\"query1\": `select version from osquery_info where version = \"2.4.0\"`,\n\t\t\t\t},\n\t\t\t\tAccelerateSeconds: 30,\n\t\t\t}, nil\n\t\t},\n\t\tfunc(ctx context.Context, res []Result) error {\n\t\t\treturn nil\n\t\t},\n\t)\n\n\t// Call getQueries\n\tresp := plugin.Call(context.Background(), osquery.ExtensionPluginRequest{\"action\": \"getQueries\"})\n\tassert.Equal(t, &StatusOK, resp.Status)\n\tif assert.Len(t, resp.Response, 1) {\n\t\tassert.JSONEq(t, `{\"queries\": {\"query1\": \"select * from time\"}, \"discovery\": {\"query1\": \"select version from osquery_info where version = \\\"2.4.0\\\"\"}, \"accelerate\": 30}`,\n\t\t\tresp.Response[0][\"results\"])\n\t}\n}\n\nfunc TestDistributedPluginErrors(t *testing.T) {\n\tvar getCalled, writeCalled bool\n\tplugin := NewPlugin(\n\t\t\"mock\",\n\t\tfunc(context.Context) (*GetQueriesResult, error) {\n\t\t\tgetCalled = true\n\t\t\treturn nil, errors.New(\"getQueries failed\")\n\t\t},\n\t\tfunc(ctx context.Context, res []Result) error {\n\t\t\twriteCalled = true\n\t\t\treturn errors.New(\"writeResults failed\")\n\t\t},\n\t)\n\n\t// Call with bad actions\n\tassert.Equal(t, int32(1), plugin.Call(context.Background(), osquery.ExtensionPluginRequest{}).Status.Code)\n\tassert.False(t, getCalled)\n\tassert.False(t, writeCalled)\n\tassert.Equal(t, int32(1), plugin.Call(context.Background(), osquery.ExtensionPluginRequest{\"action\": \"bad\"}).Status.Code)\n\tassert.False(t, getCalled)\n\tassert.False(t, writeCalled)\n\n\t// Call with good action but getQueries fails\n\tresp := plugin.Call(context.Background(), osquery.ExtensionPluginRequest{\"action\": \"getQueries\"})\n\tassert.True(t, getCalled)\n\tassert.False(t, writeCalled)\n\tassert.Equal(t, int32(1), resp.Status.Code)\n\tassert.Equal(t, \"error getting queries: getQueries failed\", resp.Status.Message)\n\n\tgetCalled = false\n\n\t// Call with good action but writeResults fails\n\t// Error unmarshalling results\n\tresp = plugin.Call(context.Background(), osquery.ExtensionPluginRequest{\"action\": \"writeResults\", \"results\": \"foobar\"})\n\tassert.False(t, getCalled)\n\tassert.False(t, writeCalled)\n\tassert.Equal(t, int32(1), resp.Status.Code)\n\tassert.Contains(t, resp.Status.Message, \"error unmarshalling results\")\n\n\t// Error converting status\n\tresp = plugin.Call(context.Background(), osquery.ExtensionPluginRequest{\"action\": \"writeResults\", \"results\": `{\"statuses\": {\"query1\": \"foo\"}}`})\n\tassert.False(t, getCalled)\n\tassert.False(t, writeCalled)\n\tassert.Equal(t, int32(1), resp.Status.Code)\n\tassert.Contains(t, resp.Status.Message, `error unmarshalling results: json: cannot unmarshal`)\n\n\t// Error unmarshalling results\n\tresp = plugin.Call(context.Background(), osquery.ExtensionPluginRequest{\"action\": \"writeResults\", \"results\": \"{}\"})\n\tassert.False(t, getCalled)\n\tassert.True(t, writeCalled)\n\tassert.Equal(t, int32(1), resp.Status.Code)\n\tassert.Contains(t, resp.Status.Message, \"error writing results\")\n}\n\nvar rawJsonQuery = \"{\\\"queries\\\":{\\\"kolide_detail_query_network_interface\\\":[{\\\"interface\\\":\\\"en0\\\",\\\"mac\\\":\\\"78:4f:43:9c:3c:8d\\\",\\\"type\\\":\\\"\\\",\\\"mtu\\\":\\\"1500\\\",\\\"metric\\\":\\\"0\\\",\\\"ipackets\\\":\\\"7071136\\\",\\\"opackets\\\":\\\"6408727\\\",\\\"ibytes\\\":\\\"1481456771\\\",\\\"obytes\\\":\\\"1633052673\\\",\\\"ierrors\\\":\\\"0\\\",\\\"oerrors\\\":\\\"0\\\",\\\"idrops\\\":\\\"0\\\",\\\"odrops\\\":\\\"0\\\",\\\"last_change\\\":\\\"1501077669\\\",\\\"description\\\":\\\"\\\",\\\"manufacturer\\\":\\\"\\\",\\\"connection_id\\\":\\\"\\\",\\\"connection_status\\\":\\\"\\\",\\\"enabled\\\":\\\"\\\",\\\"physical_adapter\\\":\\\"\\\",\\\"speed\\\":\\\"\\\",\\\"dhcp_enabled\\\":\\\"\\\",\\\"dhcp_lease_expires\\\":\\\"\\\",\\\"dhcp_lease_obtained\\\":\\\"\\\",\\\"dhcp_server\\\":\\\"\\\",\\\"dns_domain\\\":\\\"\\\",\\\"dns_domain_suffix_search_order\\\":\\\"\\\",\\\"dns_host_name\\\":\\\"\\\",\\\"dns_server_search_order\\\":\\\"\\\",\\\"interface\\\":\\\"en0\\\",\\\"address\\\":\\\"192.168.1.135\\\",\\\"mask\\\":\\\"255.255.255.0\\\",\\\"broadcast\\\":\\\"192.168.1.255\\\",\\\"point_to_point\\\":\\\"\\\",\\\"type\\\":\\\"\\\"}],\\\"kolide_detail_query_os_version\\\":[{\\\"name\\\":\\\"Mac OS X\\\",\\\"version\\\":\\\"10.12.6\\\",\\\"major\\\":\\\"10\\\",\\\"minor\\\":\\\"12\\\",\\\"patch\\\":\\\"6\\\",\\\"build\\\":\\\"16G29\\\",\\\"platform\\\":\\\"darwin\\\",\\\"platform_like\\\":\\\"darwin\\\",\\\"codename\\\":\\\"\\\"}],\\\"kolide_detail_query_osquery_flags\\\":[{\\\"name\\\":\\\"config_refresh\\\",\\\"value\\\":\\\"10\\\"},{\\\"name\\\":\\\"distributed_interval\\\",\\\"value\\\":\\\"10\\\"},{\\\"name\\\":\\\"logger_tls_period\\\",\\\"value\\\":\\\"10\\\"}],\\\"kolide_detail_query_osquery_info\\\":[{\\\"pid\\\":\\\"75680\\\",\\\"uuid\\\":\\\"DE56C776-2F5A-56DF-81C7-F64EE1BBEC8C\\\",\\\"instance_id\\\":\\\"89f267fa-9a17-4a73-87d6-05197491f2e8\\\",\\\"version\\\":\\\"2.5.0\\\",\\\"config_hash\\\":\\\"960121acb9bcbb136ce49fe77000752f237fd0dd\\\",\\\"config_valid\\\":\\\"1\\\",\\\"extensions\\\":\\\"active\\\",\\\"build_platform\\\":\\\"darwin\\\",\\\"build_distro\\\":\\\"10.12\\\",\\\"start_time\\\":\\\"1502371429\\\",\\\"watcher\\\":\\\"75678\\\"}],\\\"kolide_detail_query_system_info\\\":[{\\\"hostname\\\":\\\"Johns-MacBook-Pro.local\\\",\\\"uuid\\\":\\\"DE56C776-2F5A-56DF-81C7-F64EE1BBEC8C\\\",\\\"cpu_type\\\":\\\"x86_64h\\\",\\\"cpu_subtype\\\":\\\"Intel x86-64h Haswell\\\",\\\"cpu_brand\\\":\\\"Intel(R) Core(TM) i7-6820HQ CPU @ 2.70GHz\\\",\\\"cpu_physical_cores\\\":\\\"4\\\",\\\"cpu_logical_cores\\\":\\\"8\\\",\\\"physical_memory\\\":\\\"17179869184\\\",\\\"hardware_vendor\\\":\\\"Apple Inc.\\\",\\\"hardware_model\\\":\\\"MacBookPro13,3\\\",\\\"hardware_version\\\":\\\"1.0\\\",\\\"hardware_serial\\\":\\\"C02SP067H040\\\",\\\"computer_name\\\":\\\"\\\",\\\"local_hostname\\\":\\\"Johns-MacBook-Pro\\\"}],\\\"kolide_detail_query_uptime\\\":[{\\\"days\\\":\\\"21\\\",\\\"hours\\\":\\\"18\\\",\\\"minutes\\\":\\\"44\\\",\\\"seconds\\\":\\\"28\\\",\\\"total_seconds\\\":\\\"1881868\\\"}],\\\"kolide_label_query_6\\\":[{\\\"1\\\":\\\"1\\\"}],\\\"kolide_label_query_9\\\":\\\"\\\",\\\"kolide_detail_query_network_interface\\\":[{\\\"interface\\\":\\\"en0\\\",\\\"mac\\\":\\\"78:4f:43:9c:3c:8d\\\",\\\"type\\\":\\\"\\\",\\\"mtu\\\":\\\"1500\\\",\\\"metric\\\":\\\"0\\\",\\\"ipackets\\\":\\\"7071178\\\",\\\"opackets\\\":\\\"6408775\\\",\\\"ibytes\\\":\\\"1481473778\\\",\\\"obytes\\\":\\\"1633061382\\\",\\\"ierrors\\\":\\\"0\\\",\\\"oerrors\\\":\\\"0\\\",\\\"idrops\\\":\\\"0\\\",\\\"odrops\\\":\\\"0\\\",\\\"last_change\\\":\\\"1501077680\\\",\\\"description\\\":\\\"\\\",\\\"manufacturer\\\":\\\"\\\",\\\"connection_id\\\":\\\"\\\",\\\"connection_status\\\":\\\"\\\",\\\"enabled\\\":\\\"\\\",\\\"physical_adapter\\\":\\\"\\\",\\\"speed\\\":\\\"\\\",\\\"dhcp_enabled\\\":\\\"\\\",\\\"dhcp_lease_expires\\\":\\\"\\\",\\\"dhcp_lease_obtained\\\":\\\"\\\",\\\"dhcp_server\\\":\\\"\\\",\\\"dns_domain\\\":\\\"\\\",\\\"dns_domain_suffix_search_order\\\":\\\"\\\",\\\"dns_host_name\\\":\\\"\\\",\\\"dns_server_search_order\\\":\\\"\\\",\\\"interface\\\":\\\"en0\\\",\\\"address\\\":\\\"192.168.1.135\\\",\\\"mask\\\":\\\"255.255.255.0\\\",\\\"broadcast\\\":\\\"192.168.1.255\\\",\\\"point_to_point\\\":\\\"\\\",\\\"type\\\":\\\"\\\"}],\\\"kolide_detail_query_os_version\\\":[{\\\"name\\\":\\\"Mac OS X\\\",\\\"version\\\":\\\"10.12.6\\\",\\\"major\\\":\\\"10\\\",\\\"minor\\\":\\\"12\\\",\\\"patch\\\":\\\"6\\\",\\\"build\\\":\\\"16G29\\\",\\\"platform\\\":\\\"darwin\\\",\\\"platform_like\\\":\\\"darwin\\\",\\\"codename\\\":\\\"\\\"}],\\\"kolide_detail_query_osquery_flags\\\":[{\\\"name\\\":\\\"config_refresh\\\",\\\"value\\\":\\\"10\\\"},{\\\"name\\\":\\\"distributed_interval\\\",\\\"value\\\":\\\"10\\\"},{\\\"name\\\":\\\"logger_tls_period\\\",\\\"value\\\":\\\"10\\\"}],\\\"kolide_detail_query_osquery_info\\\":[{\\\"pid\\\":\\\"75680\\\",\\\"uuid\\\":\\\"DE56C776-2F5A-56DF-81C7-F64EE1BBEC8C\\\",\\\"instance_id\\\":\\\"89f267fa-9a17-4a73-87d6-05197491f2e8\\\",\\\"version\\\":\\\"2.5.0\\\",\\\"config_hash\\\":\\\"960121acb9bcbb136ce49fe77000752f237fd0dd\\\",\\\"config_valid\\\":\\\"1\\\",\\\"extensions\\\":\\\"active\\\",\\\"build_platform\\\":\\\"darwin\\\",\\\"build_distro\\\":\\\"10.12\\\",\\\"start_time\\\":\\\"1502371429\\\",\\\"watcher\\\":\\\"75678\\\"}],\\\"kolide_detail_query_system_info\\\":[{\\\"hostname\\\":\\\"Johns-MacBook-Pro.local\\\",\\\"uuid\\\":\\\"DE56C776-2F5A-56DF-81C7-F64EE1BBEC8C\\\",\\\"cpu_type\\\":\\\"x86_64h\\\",\\\"cpu_subtype\\\":\\\"Intel x86-64h Haswell\\\",\\\"cpu_brand\\\":\\\"Intel(R) Core(TM) i7-6820HQ CPU @ 2.70GHz\\\",\\\"cpu_physical_cores\\\":\\\"4\\\",\\\"cpu_logical_cores\\\":\\\"8\\\",\\\"physical_memory\\\":\\\"17179869184\\\",\\\"hardware_vendor\\\":\\\"Apple Inc.\\\",\\\"hardware_model\\\":\\\"MacBookPro13,3\\\",\\\"hardware_version\\\":\\\"1.0\\\",\\\"hardware_serial\\\":\\\"C02SP067H040\\\",\\\"computer_name\\\":\\\"\\\",\\\"local_hostname\\\":\\\"Johns-MacBook-Pro\\\"}],\\\"kolide_detail_query_uptime\\\":[{\\\"days\\\":\\\"21\\\",\\\"hours\\\":\\\"18\\\",\\\"minutes\\\":\\\"44\\\",\\\"seconds\\\":\\\"38\\\",\\\"total_seconds\\\":\\\"1881878\\\"}],\\\"kolide_label_query_6\\\":[{\\\"1\\\":\\\"1\\\"}],\\\"kolide_label_query_9\\\":\\\"\\\",\\\"kolide_detail_query_network_interface\\\":[{\\\"interface\\\":\\\"en0\\\",\\\"mac\\\":\\\"78:4f:43:9c:3c:8d\\\",\\\"type\\\":\\\"\\\",\\\"mtu\\\":\\\"1500\\\",\\\"metric\\\":\\\"0\\\",\\\"ipackets\\\":\\\"7071216\\\",\\\"opackets\\\":\\\"6408814\\\",\\\"ibytes\\\":\\\"1481486677\\\",\\\"obytes\\\":\\\"1633066361\\\",\\\"ierrors\\\":\\\"0\\\",\\\"oerrors\\\":\\\"0\\\",\\\"idrops\\\":\\\"0\\\",\\\"odrops\\\":\\\"0\\\",\\\"last_change\\\":\\\"1501077688\\\",\\\"description\\\":\\\"\\\",\\\"manufacturer\\\":\\\"\\\",\\\"connection_id\\\":\\\"\\\",\\\"connection_status\\\":\\\"\\\",\\\"enabled\\\":\\\"\\\",\\\"physical_adapter\\\":\\\"\\\",\\\"speed\\\":\\\"\\\",\\\"dhcp_enabled\\\":\\\"\\\",\\\"dhcp_lease_expires\\\":\\\"\\\",\\\"dhcp_lease_obtained\\\":\\\"\\\",\\\"dhcp_server\\\":\\\"\\\",\\\"dns_domain\\\":\\\"\\\",\\\"dns_domain_suffix_search_order\\\":\\\"\\\",\\\"dns_host_name\\\":\\\"\\\",\\\"dns_server_search_order\\\":\\\"\\\",\\\"interface\\\":\\\"en0\\\",\\\"address\\\":\\\"192.168.1.135\\\",\\\"mask\\\":\\\"255.255.255.0\\\",\\\"broadcast\\\":\\\"192.168.1.255\\\",\\\"point_to_point\\\":\\\"\\\",\\\"type\\\":\\\"\\\"}],\\\"kolide_detail_query_os_version\\\":[{\\\"name\\\":\\\"Mac OS X\\\",\\\"version\\\":\\\"10.12.6\\\",\\\"major\\\":\\\"10\\\",\\\"minor\\\":\\\"12\\\",\\\"patch\\\":\\\"6\\\",\\\"build\\\":\\\"16G29\\\",\\\"platform\\\":\\\"darwin\\\",\\\"platform_like\\\":\\\"darwin\\\",\\\"codename\\\":\\\"\\\"}],\\\"kolide_detail_query_osquery_flags\\\":[{\\\"name\\\":\\\"config_refresh\\\",\\\"value\\\":\\\"10\\\"},{\\\"name\\\":\\\"distributed_interval\\\",\\\"value\\\":\\\"10\\\"},{\\\"name\\\":\\\"logger_tls_period\\\",\\\"value\\\":\\\"10\\\"}],\\\"kolide_detail_query_osquery_info\\\":[{\\\"pid\\\":\\\"75680\\\",\\\"uuid\\\":\\\"DE56C776-2F5A-56DF-81C7-F64EE1BBEC8C\\\",\\\"instance_id\\\":\\\"89f267fa-9a17-4a73-87d6-05197491f2e8\\\",\\\"version\\\":\\\"2.5.0\\\",\\\"config_hash\\\":\\\"960121acb9bcbb136ce49fe77000752f237fd0dd\\\",\\\"config_valid\\\":\\\"1\\\",\\\"extensions\\\":\\\"active\\\",\\\"build_platform\\\":\\\"darwin\\\",\\\"build_distro\\\":\\\"10.12\\\",\\\"start_time\\\":\\\"1502371429\\\",\\\"watcher\\\":\\\"75678\\\"}],\\\"kolide_detail_query_system_info\\\":[{\\\"hostname\\\":\\\"Johns-MacBook-Pro.local\\\",\\\"uuid\\\":\\\"DE56C776-2F5A-56DF-81C7-F64EE1BBEC8C\\\",\\\"cpu_type\\\":\\\"x86_64h\\\",\\\"cpu_subtype\\\":\\\"Intel x86-64h Haswell\\\",\\\"cpu_brand\\\":\\\"Intel(R) Core(TM) i7-6820HQ CPU @ 2.70GHz\\\",\\\"cpu_physical_cores\\\":\\\"4\\\",\\\"cpu_logical_cores\\\":\\\"8\\\",\\\"physical_memory\\\":\\\"17179869184\\\",\\\"hardware_vendor\\\":\\\"Apple Inc.\\\",\\\"hardware_model\\\":\\\"MacBookPro13,3\\\",\\\"hardware_version\\\":\\\"1.0\\\",\\\"hardware_serial\\\":\\\"C02SP067H040\\\",\\\"computer_name\\\":\\\"\\\",\\\"local_hostname\\\":\\\"Johns-MacBook-Pro\\\"}],\\\"kolide_detail_query_uptime\\\":[{\\\"days\\\":\\\"21\\\",\\\"hours\\\":\\\"18\\\",\\\"minutes\\\":\\\"44\\\",\\\"seconds\\\":\\\"49\\\",\\\"total_seconds\\\":\\\"1881889\\\"}],\\\"kolide_label_query_6\\\":[{\\\"1\\\":\\\"1\\\"}],\\\"kolide_label_query_9\\\":\\\"\\\"},\\\"statuses\\\":{\\\"kolide_detail_query_network_interface\\\":\\\"0\\\",\\\"kolide_detail_query_os_version\\\":\\\"0\\\",\\\"kolide_detail_query_osquery_flags\\\":\\\"0\\\",\\\"kolide_detail_query_osquery_info\\\":\\\"0\\\",\\\"kolide_detail_query_system_info\\\":\\\"0\\\",\\\"kolide_detail_query_uptime\\\":\\\"0\\\",\\\"kolide_label_query_6\\\":\\\"0\\\",\\\"kolide_label_query_9\\\":\\\"0\\\"}}\\n\"\n\nfunc TestUnmarshalResults(t *testing.T) {\n\tvar rs ResultsStruct\n\terr := json.NewDecoder(bytes.NewBufferString(rawJsonQuery)).Decode(&rs)\n\trequire.Nil(t, err)\n\tresults, err := rs.toResults()\n\trequire.Nil(t, err)\n\tassert.Len(t, results, 8)\n}\n\nfunc TestUnmarshalStatus(t *testing.T) {\n\ttestCases := []struct {\n\t\tjson     []byte\n\t\tsuccess  bool\n\t\texpected OsqueryInt\n\t}{\n\t\t{[]byte{}, true, 0},\n\t\t{[]byte(`\"\"`), true, 0},\n\t\t{[]byte(`\"23\"`), true, 23},\n\t\t{[]byte(`\"0000\"`), true, 0},\n\t\t{[]byte(`\"-12\"`), true, -12},\n\t\t{[]byte(`\"0\"`), true, 0},\n\t\t{[]byte(`\"foo\"`), false, 0},\n\t\t{[]byte(`0`), true, 0},\n\t\t{[]byte(`1`), true, 1},\n\t}\n\tfor i, testCase := range testCases {\n\t\tt.Run(fmt.Sprintf(\"#%.2d\", i), func(t *testing.T) {\n\t\t\tvar i OsqueryInt\n\t\t\terr := i.UnmarshalJSON(testCase.json)\n\t\t\trequire.Equal(t, testCase.success, (err == nil), fmt.Sprintf(\"Trying to convert %s\", string(testCase.json)))\n\t\t\tassert.Equal(t, testCase.expected, i)\n\t\t})\n\t}\n}\n\nfunc TestHandleResults(t *testing.T) {\n\tcalled := false\n\tvar results []Result\n\tplugin := NewPlugin(\n\t\t\"mock\",\n\t\tnil,\n\t\tfunc(ctx context.Context, res []Result) error {\n\t\t\tcalled = true\n\t\t\tresults = res\n\t\t\treturn nil\n\t\t},\n\t)\n\tresp := plugin.Call(context.Background(), osquery.ExtensionPluginRequest{\"action\": \"writeResults\", \"results\": rawJsonQuery})\n\trequire.True(t, called)\n\tassert.Len(t, results, 8)\n\tassert.Equal(t, &StatusOK, resp.Status)\n}\n"
  },
  {
    "path": "plugin/logger/logger.go",
    "content": "// Package logger creates an osquery logging plugin.\n//\n// See https://osquery.readthedocs.io/en/latest/development/logger-plugins/ for more.\npackage logger\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/json\"\n\n\t\"github.com/osquery/osquery-go/gen/osquery\"\n)\n\n// LogFunc is the logger function used by an osquery Logger plugin.\n//\n// The LogFunc should log the provided result string. The LogType\n// argument can be optionally used to log differently depending on the\n// type of log received. The context argument can optionally be used\n// for cancellation in long-running operations.\ntype LogFunc func(ctx context.Context, typ LogType, log string) error\n\n// Plugin is an osquery logger plugin.\n// The Plugin struct implements the OsqueryPlugin interface.\ntype Plugin struct {\n\tname  string\n\tlogFn LogFunc\n}\n\n// NewPlugin takes a value that implements LoggerPlugin and wraps it with\n// the appropriate methods to satisfy the OsqueryPlugin interface. Use this to\n// easily create plugins implementing osquery loggers.\nfunc NewPlugin(name string, fn LogFunc) *Plugin {\n\treturn &Plugin{name: name, logFn: fn}\n}\n\nfunc (t *Plugin) Name() string {\n\treturn t.name\n}\n\nfunc (t *Plugin) RegistryName() string {\n\treturn \"logger\"\n}\n\nfunc (t *Plugin) Routes() osquery.ExtensionPluginResponse {\n\treturn []map[string]string{}\n}\n\nfunc (t *Plugin) Ping() osquery.ExtensionStatus {\n\treturn osquery.ExtensionStatus{Code: 0, Message: \"OK\"}\n}\n\nfunc (t *Plugin) Call(ctx context.Context, request osquery.ExtensionPluginRequest) osquery.ExtensionResponse {\n\tvar err error\n\tif log, ok := request[\"string\"]; ok {\n\t\terr = t.logFn(ctx, LogTypeString, log)\n\t} else if log, ok := request[\"snapshot\"]; ok {\n\t\terr = t.logFn(ctx, LogTypeSnapshot, log)\n\t} else if log, ok := request[\"health\"]; ok {\n\t\terr = t.logFn(ctx, LogTypeHealth, log)\n\t} else if log, ok := request[\"init\"]; ok {\n\t\terr = t.logFn(ctx, LogTypeInit, log)\n\t} else if _, ok := request[\"status\"]; ok {\n\t\tstatusJSON := []byte(request[\"log\"])\n\t\tif len(statusJSON) == 0 {\n\t\t\treturn osquery.ExtensionResponse{\n\t\t\t\tStatus: &osquery.ExtensionStatus{\n\t\t\t\t\tCode:    1,\n\t\t\t\t\tMessage: \"got empty status\",\n\t\t\t\t},\n\t\t\t}\n\t\t}\n\n\t\t// Dirty hack because osquery gives us malformed JSON.\n\t\tstatusJSON = bytes.Replace(statusJSON, []byte(`\"\":`), []byte(``), -1)\n\t\tstatusJSON[0] = '['\n\t\tstatusJSON[len(statusJSON)-1] = ']'\n\n\t\tvar parsedStatuses []json.RawMessage\n\t\tif err := json.Unmarshal(statusJSON, &parsedStatuses); err != nil {\n\t\t\treturn osquery.ExtensionResponse{\n\t\t\t\tStatus: &osquery.ExtensionStatus{\n\t\t\t\t\tCode:    1,\n\t\t\t\t\tMessage: \"error parsing status logs: \" + err.Error(),\n\t\t\t\t},\n\t\t\t}\n\t\t}\n\n\t\tfor _, s := range parsedStatuses {\n\t\t\terr = t.logFn(ctx, LogTypeStatus, string(s))\n\t\t}\n\t} else {\n\t\treturn osquery.ExtensionResponse{\n\t\t\tStatus: &osquery.ExtensionStatus{\n\t\t\t\tCode:    1,\n\t\t\t\tMessage: \"unknown log request\",\n\t\t\t},\n\t\t}\n\t}\n\n\tif err != nil {\n\t\treturn osquery.ExtensionResponse{\n\t\t\tStatus: &osquery.ExtensionStatus{\n\t\t\t\tCode:    1,\n\t\t\t\tMessage: \"error logging: \" + err.Error(),\n\t\t\t},\n\t\t}\n\t}\n\n\treturn osquery.ExtensionResponse{\n\t\tStatus:   &osquery.ExtensionStatus{Code: 0, Message: \"OK\"},\n\t\tResponse: osquery.ExtensionPluginResponse{},\n\t}\n}\n\nfunc (t *Plugin) Shutdown() {}\n\n// LogType encodes the type of log osquery is outputting.\ntype LogType int\n\nconst (\n\tLogTypeString LogType = iota\n\tLogTypeSnapshot\n\tLogTypeHealth\n\tLogTypeInit\n\tLogTypeStatus\n)\n\n// String implements the fmt.Stringer interface for LogType.\nfunc (l LogType) String() string {\n\tvar typeString string\n\tswitch l {\n\tcase LogTypeString:\n\t\ttypeString = \"string\"\n\tcase LogTypeSnapshot:\n\t\ttypeString = \"snapshot\"\n\tcase LogTypeHealth:\n\t\ttypeString = \"health\"\n\tcase LogTypeInit:\n\t\ttypeString = \"init\"\n\tcase LogTypeStatus:\n\t\ttypeString = \"status\"\n\tdefault:\n\t\ttypeString = \"unknown\"\n\t}\n\treturn typeString\n}\n"
  },
  {
    "path": "plugin/logger/logger_test.go",
    "content": "package logger\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"testing\"\n\n\t\"github.com/osquery/osquery-go/gen/osquery\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\ntype mockLoggerPlugin struct {\n\tNameFunc      func() string\n\tLogStringFunc func(context.Context, LogType, string) error\n}\n\nfunc (m *mockLoggerPlugin) Name() string {\n\treturn m.NameFunc()\n}\n\nfunc (m *mockLoggerPlugin) LogString(ctx context.Context, typ LogType, log string) error {\n\treturn m.LogStringFunc(ctx, typ, log)\n}\n\nfunc TestLoggerPlugin(t *testing.T) {\n\tvar calledType LogType\n\tvar calledLog string\n\tplugin := NewPlugin(\"mock\", func(ctx context.Context, typ LogType, log string) error {\n\t\tcalledType = typ\n\t\tcalledLog = log\n\t\treturn nil\n\t})\n\n\tStatusOK := osquery.ExtensionStatus{Code: 0, Message: \"OK\"}\n\t// Basic methods\n\tassert.Equal(t, \"logger\", plugin.RegistryName())\n\tassert.Equal(t, \"mock\", plugin.Name())\n\tassert.Equal(t, StatusOK, plugin.Ping())\n\tassert.Equal(t, osquery.ExtensionPluginResponse{}, plugin.Routes())\n\n\t// Log string\n\tresp := plugin.Call(context.Background(), osquery.ExtensionPluginRequest{\"string\": \"logged string\"})\n\tassert.Equal(t, &StatusOK, resp.Status)\n\tassert.Equal(t, LogTypeString, calledType)\n\tassert.Equal(t, \"logged string\", calledLog)\n\n\t// Log snapshot\n\tresp = plugin.Call(context.Background(), osquery.ExtensionPluginRequest{\"snapshot\": \"logged snapshot\"})\n\tassert.Equal(t, &StatusOK, resp.Status)\n\tassert.Equal(t, LogTypeSnapshot, calledType)\n\tassert.Equal(t, \"logged snapshot\", calledLog)\n\n\t// Log health\n\tresp = plugin.Call(context.Background(), osquery.ExtensionPluginRequest{\"health\": \"logged health\"})\n\tassert.Equal(t, &StatusOK, resp.Status)\n\tassert.Equal(t, LogTypeHealth, calledType)\n\tassert.Equal(t, \"logged health\", calledLog)\n\n\t// Log init\n\tresp = plugin.Call(context.Background(), osquery.ExtensionPluginRequest{\"init\": \"logged init\"})\n\tassert.Equal(t, &StatusOK, resp.Status)\n\tassert.Equal(t, LogTypeInit, calledType)\n\tassert.Equal(t, \"logged init\", calledLog)\n\n\t// Log status\n\tresp = plugin.Call(context.Background(), osquery.ExtensionPluginRequest{\"status\": \"true\", \"log\": `{\"\":{\"s\":\"0\",\"f\":\"events.cpp\",\"i\":\"828\",\"m\":\"Event publisher failed setup: kernel: Cannot access \\/dev\\/osquery\"},\"\":{\"s\":\"0\",\"f\":\"events.cpp\",\"i\":\"828\",\"m\":\"Event publisher failed setup: scnetwork: Publisher not used\"},\"\":{\"s\":\"0\",\"f\":\"scheduler.cpp\",\"i\":\"74\",\"m\":\"Executing scheduled query macos_kextstat: SELECT * FROM time\"}}`})\n\tassert.Equal(t, &StatusOK, resp.Status)\n\tassert.Equal(t, LogTypeStatus, calledType)\n\tassert.Equal(t, `{\"s\":\"0\",\"f\":\"scheduler.cpp\",\"i\":\"74\",\"m\":\"Executing scheduled query macos_kextstat: SELECT * FROM time\"}`, calledLog)\n}\n\nfunc TestLogPluginErrors(t *testing.T) {\n\tvar called bool\n\tplugin := NewPlugin(\"mock\", func(ctx context.Context, typ LogType, log string) error {\n\t\tcalled = true\n\t\treturn errors.New(\"foobar\")\n\t})\n\n\t// Call with bad actions\n\tassert.Equal(t, int32(1), plugin.Call(context.Background(), osquery.ExtensionPluginRequest{}).Status.Code)\n\tassert.False(t, called)\n\tassert.Equal(t, int32(1), plugin.Call(context.Background(), osquery.ExtensionPluginRequest{\"action\": \"bad\"}).Status.Code)\n\tassert.False(t, called)\n\n\t// Call with empty status\n\tassert.Equal(t, int32(1), plugin.Call(context.Background(), osquery.ExtensionPluginRequest{\"status\": \"true\", \"log\": \"\"}).Status.Code)\n\tassert.False(t, called)\n\n\t// Call with good action but logging fails\n\tresp := plugin.Call(context.Background(), osquery.ExtensionPluginRequest{\"string\": \"logged string\"})\n\tassert.True(t, called)\n\tassert.Equal(t, int32(1), resp.Status.Code)\n\tassert.Equal(t, \"error logging: foobar\", resp.Status.Message)\n}\n"
  },
  {
    "path": "plugin/table/column.go",
    "content": "package table\n\nimport (\n\t\"encoding/json\"\n\t\"strings\"\n)\n\n// ColumnDefinition defines the relevant information for a column in a table\n// plugin. Name and Type are mandatory. Prefer using the *Column helpers to\n// create ColumnDefinition structs.\ntype ColumnDefinition struct {\n\tName        string     `json:\"name\"`\n\tType        ColumnType `json:\"type\"`\n\tDescription string     `json:\"description,omitempty\"`\n\tNotes       string     `json:\"notes,omitempty\"`\n\n\t// Options from https://github.com/osquery/osquery/blob/master/osquery/core/sql/column.h#L37\n\tIndex      bool `json:\"index\"`\n\tRequired   bool `json:\"required\"`\n\tAdditional bool `json:\"additional\"`\n\tOptimized  bool `json:\"optimized\"`\n\tHidden     bool `json:\"hidden\"`\n}\n\n// ColumnType is a strongly typed representation of the data type string for a\n// column definition. The named constants should be used.\ntype ColumnType string\n\n// The following column types are defined in osquery tables.h.\nconst (\n\tColumnTypeUnknown        ColumnType = \"UNKNOWN\"\n\tColumnTypeText           ColumnType = \"TEXT\"\n\tColumnTypeInteger        ColumnType = \"INTEGER\"\n\tColumnTypeBigInt         ColumnType = \"BIGINT\"\n\tColumnTypeUnsignedBigInt ColumnType = \"UNSIGNED BIGINT\"\n\tColumnTypeDouble         ColumnType = \"DOUBLE\"\n\tColumnTypeBlob           ColumnType = \"BLOB\"\n)\n\n// jsonString returns the value used when marshaling ColumnType to JSON\n// (lowercase, spaces as underscores).\nfunc (ct ColumnType) jsonString() string {\n\treturn strings.ReplaceAll(strings.ToLower(string(ct)), \" \", \"_\")\n}\n\n// MarshalJSON implements json.Marshaler.\nfunc (ct ColumnType) MarshalJSON() ([]byte, error) {\n\treturn json.Marshal(ct.jsonString())\n}\n\ntype ColumnOpt func(*ColumnDefinition)\n\n// TextColumn is a helper for defining columns containing strings.\nfunc TextColumn(name string, opts ...ColumnOpt) ColumnDefinition {\n\treturn NewColumn(name, ColumnTypeText, opts...)\n}\n\n// IntegerColumn is a helper for defining columns containing integers.\nfunc IntegerColumn(name string, opts ...ColumnOpt) ColumnDefinition {\n\treturn NewColumn(name, ColumnTypeInteger, opts...)\n}\n\n// BigIntColumn is a helper for defining columns containing big integers.\nfunc BigIntColumn(name string, opts ...ColumnOpt) ColumnDefinition {\n\treturn NewColumn(name, ColumnTypeBigInt, opts...)\n}\n\n// DoubleColumn is a helper for defining columns containing floating point\n// values.\nfunc DoubleColumn(name string, opts ...ColumnOpt) ColumnDefinition {\n\treturn NewColumn(name, ColumnTypeDouble, opts...)\n}\n\n// NewColumn returns a ColumnDefinition for the specified column.\nfunc NewColumn(name string, ctype ColumnType, opts ...ColumnOpt) ColumnDefinition {\n\tcd := ColumnDefinition{\n\t\tName: name,\n\t\tType: ctype,\n\t}\n\n\tfor _, opt := range opts {\n\t\topt(&cd)\n\t}\n\n\treturn cd\n}\n\n// IndexColumn is a functional argument to declare this as an indexed\n// column. Depending on implementation, this can significantly change\n// performance.  See osquery source code for more information.\nfunc IndexColumn() ColumnOpt {\n\treturn func(cd *ColumnDefinition) {\n\t\tcd.Index = true\n\t}\n}\n\n// RequiredColumn is a functional argument that sets this as a\n// required column. sqlite will not process queries, if a required\n// column is missing. See osquery source code for more information.\nfunc RequiredColumn() ColumnOpt {\n\treturn func(cd *ColumnDefinition) {\n\t\tcd.Required = true\n\t}\n\n}\n\n// AdditionalColumn is a functional argument that sets this as an\n// additional column. See osquery source code for more information.\nfunc AdditionalColumn() ColumnOpt {\n\treturn func(cd *ColumnDefinition) {\n\t\tcd.Additional = true\n\t}\n}\n\n// OptimizedColumn is a functional argument that sets this as an\n// optimized column. See osquery source code for more information.\nfunc OptimizedColumn() ColumnOpt {\n\treturn func(cd *ColumnDefinition) {\n\t\tcd.Optimized = true\n\t}\n\n}\n\n// HiddenColumn is a functional argument that sets this as a\n// hidden column. This omits it from `select *` queries. See osquery source code for more information.\nfunc HiddenColumn() ColumnOpt {\n\treturn func(cd *ColumnDefinition) {\n\t\tcd.Hidden = true\n\t}\n}\n\n// ColumnDescription sets the column description. This is not\n// currently part of the underlying osquery api, it is here for human\n// consumption. It may become part of osquery spec generation.\nfunc ColumnDescription(d string) ColumnOpt {\n\treturn func(cd *ColumnDefinition) {\n\t\tcd.Description = d\n\t}\n}\n\n// Options returns the bitmask representation of the boolean column\n// options. This uses the values as encoded in\n// https://github.com/osquery/osquery/blob/master/osquery/core/sql/column.h#L37\nfunc (c *ColumnDefinition) Options() uint8 {\n\toptionsBitmask := uint8(0)\n\n\t// We can skip the 0: default case, because it's what you get if nothing is set.\n\toptionValues := map[uint8]bool{\n\t\t1:  c.Index,\n\t\t2:  c.Required,\n\t\t4:  c.Additional,\n\t\t8:  c.Optimized,\n\t\t16: c.Hidden,\n\t}\n\n\tfor v, b := range optionValues {\n\t\tif b {\n\t\t\toptionsBitmask = optionsBitmask | v\n\t\t}\n\t}\n\treturn optionsBitmask\n}\n"
  },
  {
    "path": "plugin/table/column_test.go",
    "content": "package table\n\nimport (\n\t\"encoding/json\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestColumnType_MarshalJSON(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tct       ColumnType\n\t\texpected string\n\t}{\n\t\t{ColumnTypeUnknown, `\"unknown\"`},\n\t\t{ColumnTypeText, `\"text\"`},\n\t\t{ColumnTypeInteger, `\"integer\"`},\n\t\t{ColumnTypeBigInt, `\"bigint\"`},\n\t\t{ColumnTypeUnsignedBigInt, `\"unsigned_bigint\"`},\n\t\t{ColumnTypeDouble, `\"double\"`},\n\t\t{ColumnTypeBlob, `\"blob\"`},\n\t\t{ColumnType(\"CUSTOM TYPE\"), `\"custom_type\"`},\n\t}\n\n\tfor _, tt := range tests {\n\t\tgot, err := json.Marshal(tt.ct)\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, tt.expected, string(got))\n\t}\n}\n\nfunc TestColumnDefinition_Options(t *testing.T) {\n\tt.Parallel()\n\n\t// Option bitmask values from osquery column.h: Index=1, Required=2, Additional=4, Optimized=8, Hidden=16\n\ttests := []struct {\n\t\tname     string\n\t\tin       []ColumnOpt\n\t\texpected uint8\n\t}{\n\t\t{\n\t\t\tname:     \"no options\",\n\t\t\tin:       []ColumnOpt{},\n\t\t\texpected: 0,\n\t\t},\n\t\t{\n\t\t\tname:     \"Index only\",\n\t\t\tin:       []ColumnOpt{IndexColumn()},\n\t\t\texpected: 1,\n\t\t},\n\t\t{\n\t\t\tname:     \"Required only\",\n\t\t\tin:       []ColumnOpt{RequiredColumn()},\n\t\t\texpected: 2,\n\t\t},\n\t\t{\n\t\t\tname:     \"Additional only\",\n\t\t\tin:       []ColumnOpt{AdditionalColumn()},\n\t\t\texpected: 4,\n\t\t},\n\t\t{\n\t\t\tname:     \"Optimized only\",\n\t\t\tin:       []ColumnOpt{OptimizedColumn()},\n\t\t\texpected: 8,\n\t\t},\n\t\t{\n\t\t\tname:     \"Hidden only\",\n\t\t\tin:       []ColumnOpt{HiddenColumn()},\n\t\t\texpected: 16,\n\t\t},\n\t\t{\n\t\t\tname:     \"Index and Hidden\",\n\t\t\tin:       []ColumnOpt{IndexColumn(), HiddenColumn()},\n\t\t\texpected: 17,\n\t\t},\n\t\t{\n\t\t\tname:     \"all options\",\n\t\t\tin:       []ColumnOpt{IndexColumn(), RequiredColumn(), AdditionalColumn(), OptimizedColumn(), HiddenColumn()},\n\t\t\texpected: 1 + 2 + 4 + 8 + 16,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tcd := TextColumn(\"foo\", tt.in...)\n\t\t\trequire.Equal(t, tt.expected, cd.Options())\n\t\t})\n\t}\n}\n\nfunc TestColumnOpts_set_fields(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"IndexColumn sets Index\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tcd := TextColumn(\"c\", IndexColumn())\n\t\trequire.True(t, cd.Index)\n\t\trequire.False(t, cd.Required)\n\t})\n\tt.Run(\"RequiredColumn sets Required\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tcd := TextColumn(\"c\", RequiredColumn())\n\t\trequire.True(t, cd.Required)\n\t})\n\tt.Run(\"AdditionalColumn sets Additional\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tcd := TextColumn(\"c\", AdditionalColumn())\n\t\trequire.True(t, cd.Additional)\n\t})\n\tt.Run(\"OptimizedColumn sets Optimized\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tcd := TextColumn(\"c\", OptimizedColumn())\n\t\trequire.True(t, cd.Optimized)\n\t})\n\tt.Run(\"HiddenColumn sets Hidden\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tcd := TextColumn(\"c\", HiddenColumn())\n\t\trequire.True(t, cd.Hidden)\n\t})\n\tt.Run(\"ColumnDescription sets Description\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tcd := TextColumn(\"c\", ColumnDescription(\"human-readable note\"))\n\t\trequire.Equal(t, \"human-readable note\", cd.Description)\n\t})\n\tt.Run(\"multiple opts apply in order\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tcd := TextColumn(\"c\", IndexColumn(), ColumnDescription(\"desc\"), RequiredColumn())\n\t\trequire.True(t, cd.Index)\n\t\trequire.True(t, cd.Required)\n\t\trequire.Equal(t, \"desc\", cd.Description)\n\t})\n}\n\nfunc TestColumn_helpers_produce_correct_type(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tname   string\n\t\tcolumn ColumnDefinition\n\t\twant   ColumnType\n\t}{\n\t\t{\"TextColumn\", TextColumn(\"x\"), ColumnTypeText},\n\t\t{\"IntegerColumn\", IntegerColumn(\"x\"), ColumnTypeInteger},\n\t\t{\"BigIntColumn\", BigIntColumn(\"x\"), ColumnTypeBigInt},\n\t\t{\"DoubleColumn\", DoubleColumn(\"x\"), ColumnTypeDouble},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\trequire.Equal(t, tt.want, tt.column.Type)\n\t\t\trequire.Equal(t, \"x\", tt.column.Name)\n\t\t})\n\t}\n}\n\nfunc TestNewColumn_applies_opts(t *testing.T) {\n\tt.Parallel()\n\n\tcd := NewColumn(\"custom\", ColumnTypeBlob, IndexColumn(), ColumnDescription(\"blob col\"))\n\trequire.Equal(t, \"custom\", cd.Name)\n\trequire.Equal(t, ColumnType(\"BLOB\"), cd.Type)\n\trequire.True(t, cd.Index)\n\trequire.Equal(t, \"blob col\", cd.Description)\n}\n"
  },
  {
    "path": "plugin/table/spec.go",
    "content": "package table\n\n// OsqueryTableSpec is a struct compatible with the osquery spec files. It\n// can be marshalled to json if desired.\ntype OsqueryTableSpec struct {\n\tName        string             `json:\"name\"`\n\tDescription string             `json:\"description\"`\n\tUrl         string             `json:\"url\"`\n\tPlatforms   []platformName     `json:\"platforms\"`\n\tEvented     bool               `json:\"evented\"`\n\tCacheable   bool               `json:\"cacheable\"`\n\tNotes       string             `json:\"notes,omitempty\"`\n\tExamples    []string           `json:\"examples,omitempty\"`\n\tColumns     []ColumnDefinition `json:\"columns\"`\n}\n\nfunc (t *Plugin) Spec() OsqueryTableSpec {\n\treturn OsqueryTableSpec{\n\t\tName:        t.name,\n\t\tDescription: t.description,\n\t\tUrl:         t.url,\n\t\tPlatforms:   t.platforms,\n\t\tNotes:       t.notes,\n\t\tExamples:    t.examples,\n\t\tColumns:     t.columns,\n\t}\n}\n"
  },
  {
    "path": "plugin/table/spec_test.go",
    "content": "package table\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestTable_Spec(t *testing.T) {\n\tt.Parallel()\n\n\tmockGenerate := func(_ context.Context, _ QueryContext) ([]map[string]string, error) { return nil, nil }\n\n\ttests := []struct {\n\t\tname     string\n\t\tplugin   *Plugin\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname: \"single text column\",\n\t\t\tplugin: NewPlugin(\"simple\", []ColumnDefinition{TextColumn(\"simple_text\")}, mockGenerate,\n\t\t\t\tWithPlatforms(DarwinPlatform),\n\t\t\t),\n\t\t\texpected: `{\n  \"name\": \"simple\",\n  \"cacheable\": false,\n  \"evented\": false,\n  \"columns\": [\n    { \"name\": \"simple_text\", \"type\": \"TEXT\", \"index\": false, \"required\": false, \"additional\": false, \"optimized\": false, \"hidden\": false }\n  ],\n  \"description\": \"\",\n  \"url\": \"\",\n  \"platforms\": [\"darwin\"]\n}`,\n\t\t},\n\t\t{\n\t\t\tname: \"multiple columns with mixed types\",\n\t\t\tplugin: NewPlugin(\"mixed\", []ColumnDefinition{\n\t\t\t\tTextColumn(\"name\"),\n\t\t\t\tIntegerColumn(\"pid\"),\n\t\t\t\tBigIntColumn(\"size\"),\n\t\t\t\tDoubleColumn(\"score\"),\n\t\t\t}, mockGenerate,\n\t\t\t\tWithPlatforms(DarwinPlatform),\n\t\t\t),\n\t\t\texpected: `{\n  \"name\": \"mixed\",\n  \"cacheable\": false,\n  \"evented\": false,\n  \"columns\": [\n    { \"name\": \"name\", \"type\": \"TEXT\", \"index\": false, \"required\": false, \"additional\": false, \"optimized\": false, \"hidden\": false },\n    { \"name\": \"pid\", \"type\": \"INTEGER\", \"index\": false, \"required\": false, \"additional\": false, \"optimized\": false, \"hidden\": false },\n    { \"name\": \"size\", \"type\": \"BIGINT\", \"index\": false, \"required\": false, \"additional\": false, \"optimized\": false, \"hidden\": false },\n    { \"name\": \"score\", \"type\": \"DOUBLE\", \"index\": false, \"required\": false, \"additional\": false, \"optimized\": false, \"hidden\": false }\n  ],\n  \"description\": \"\",\n  \"url\": \"\",\n  \"platforms\": [\"darwin\"]\n}`,\n\t\t},\n\t\t{\n\t\t\tname: \"columns with options\",\n\t\t\tplugin: NewPlugin(\"opts\", []ColumnDefinition{\n\t\t\t\tTextColumn(\"key\", IndexColumn(), RequiredColumn()),\n\t\t\t\tIntegerColumn(\"count\", HiddenColumn()),\n\t\t\t}, mockGenerate,\n\t\t\t\tWithPlatforms(DarwinPlatform),\n\t\t\t),\n\t\t\texpected: `{\n  \"name\": \"opts\",\n  \"cacheable\": false,\n  \"evented\": false,\n  \"columns\": [\n    { \"name\": \"key\", \"type\": \"TEXT\", \"index\": true, \"required\": true, \"additional\": false, \"optimized\": false, \"hidden\": false },\n    { \"name\": \"count\", \"type\": \"INTEGER\", \"index\": false, \"required\": false, \"additional\": false, \"optimized\": false, \"hidden\": true }\n  ],\n  \"description\": \"\",\n  \"url\": \"\",\n  \"platforms\": [\"darwin\"]\n}`,\n\t\t},\n\t\t{\n\t\t\tname: \"plugin with description, url, notes, examples, platforms\",\n\t\t\tplugin: NewPlugin(\"full\", []ColumnDefinition{TextColumn(\"id\")}, mockGenerate,\n\t\t\t\tWithDescription(\"Table description\"),\n\t\t\t\tWithURL(\"https://osquery.io/schema\"),\n\t\t\t\tWithNotes(\"Some notes\"),\n\t\t\t\tWithExample(\"SELECT * FROM full\"),\n\t\t\t\tWithPlatforms(DarwinPlatform, LinuxPlatform),\n\t\t\t),\n\t\t\texpected: `{\n  \"name\": \"full\",\n  \"cacheable\": false,\n  \"evented\": false,\n  \"columns\": [\n    { \"name\": \"id\", \"type\": \"TEXT\", \"index\": false, \"required\": false, \"additional\": false, \"optimized\": false, \"hidden\": false }\n  ],\n  \"description\": \"Table description\",\n  \"url\": \"https://osquery.io/schema\",\n  \"notes\": \"Some notes\",\n  \"examples\": [\"SELECT * FROM full\"],\n  \"platforms\": [\"darwin\", \"linux\"]\n}`,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tgeneratedSpec := tt.plugin.Spec()\n\n\t\t\tvar expectedSpec OsqueryTableSpec\n\t\t\trequire.NoError(t, json.Unmarshal([]byte(tt.expected), &expectedSpec))\n\n\t\t\trequire.EqualValues(t, expectedSpec, generatedSpec, \"spec for %s\", tt.name)\n\t\t})\n\t}\n}\n\nfunc TestTable_Spec_marshal_json_column_type_format(t *testing.T) {\n\tt.Parallel()\n\n\t// ColumnType should marshal to JSON as lowercase with underscores (e.g. \"unsigned_bigint\")\n\tplugin := NewPlugin(\"t\", []ColumnDefinition{\n\t\tTextColumn(\"a\"),\n\t\tNewColumn(\"b\", ColumnTypeUnsignedBigInt),\n\t}, func(_ context.Context, _ QueryContext) ([]map[string]string, error) { return nil, nil })\n\tspec := plugin.Spec()\n\n\tdata, err := json.Marshal(spec)\n\trequire.NoError(t, err)\n\n\tvar decoded struct {\n\t\tColumns []struct {\n\t\t\tName string `json:\"name\"`\n\t\t\tType string `json:\"type\"`\n\t\t} `json:\"columns\"`\n\t}\n\trequire.NoError(t, json.Unmarshal(data, &decoded))\n\trequire.Len(t, decoded.Columns, 2)\n\trequire.Equal(t, \"text\", decoded.Columns[0].Type)\n\trequire.Equal(t, \"unsigned_bigint\", decoded.Columns[1].Type)\n}\n"
  },
  {
    "path": "plugin/table/table.go",
    "content": "// Package table creates an osquery table plugin.\npackage table\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"runtime\"\n\t\"strconv\"\n\n\t\"github.com/osquery/osquery-go/gen/osquery\"\n\t\"github.com/osquery/osquery-go/traces\"\n\t\"github.com/pkg/errors\"\n\t\"go.opentelemetry.io/otel/codes\"\n)\n\n// Generate returns the rows generated by the table. The ctx argument\n// should be checked for cancellation if the generation performs a\n// substantial amount of work. The queryContext argument provides the\n// deserialized JSON query context from osquery.\ntype GenerateFunc func(ctx context.Context, queryContext QueryContext) ([]map[string]string, error)\n\ntype Plugin struct {\n\tname        string\n\tcolumns     []ColumnDefinition\n\tgenerate    GenerateFunc\n\tdescription string\n\turl         string\n\tnotes       string\n\texamples    []string\n\tplatforms   []platformName\n}\n\ntype TableOpt func(*Plugin)\n\n// WithDescription sets the informational table description that will be used if table specs are generated\nfunc WithDescription(description string) TableOpt {\n\treturn func(tbl *Plugin) {\n\t\ttbl.description = description\n\t}\n}\n\n// WithURL sets the informational table URL that will be used if table specs are generated\nfunc WithURL(url string) TableOpt {\n\treturn func(tbl *Plugin) {\n\t\ttbl.url = url\n\t}\n}\n\n// WithNotes sets the informational table notes that will be used if table specs are generated\nfunc WithNotes(notes string) TableOpt {\n\treturn func(tbl *Plugin) {\n\t\ttbl.notes = notes\n\t}\n}\n\n// WithExample adds an informational example that will be used if table specs are generated.\n// Can be used more than once.\nfunc WithExample(example string) TableOpt {\n\treturn func(tbl *Plugin) {\n\t\ttbl.examples = append(tbl.examples, example)\n\t}\n}\n\n// WithPlatform overrides the default of runtime.GOOS with a list of supported platforms. This\n// is used by the table spec generation.\nfunc WithPlatforms(platforms ...platformName) TableOpt {\n\treturn func(tbl *Plugin) {\n\t\ttbl.platforms = platforms\n\t}\n}\nfunc NewPlugin(name string, columns []ColumnDefinition, gen GenerateFunc, opts ...TableOpt) *Plugin {\n\ttbl := &Plugin{\n\t\tname:     name,\n\t\tcolumns:  columns,\n\t\tgenerate: gen,\n\t}\n\n\tfor _, opt := range opts {\n\t\topt(tbl)\n\t}\n\n\t// If the table platform isn't set, use runtime.GOOS to determine it\n\tif len(tbl.platforms) == 0 {\n\t\tswitch runtime.GOOS {\n\t\tcase \"darwin\":\n\t\t\ttbl.platforms = []platformName{DarwinPlatform}\n\t\tcase \"windows\":\n\t\t\ttbl.platforms = []platformName{WindowsPlatform}\n\t\tcase \"linux\":\n\t\t\ttbl.platforms = []platformName{LinuxPlatform}\n\t\tdefault:\n\t\t\t// Historic function signature has no error, so there's not much to do\n\t\t\t// for an unknown platform.\n\t\t}\n\t}\n\n\treturn tbl\n}\n\nfunc (t *Plugin) Name() string {\n\treturn t.name\n}\n\nfunc (t *Plugin) RegistryName() string {\n\treturn \"table\"\n}\n\nfunc (t *Plugin) Routes() osquery.ExtensionPluginResponse {\n\troutes := []map[string]string{}\n\tfor _, col := range t.columns {\n\t\troutes = append(routes, map[string]string{\n\t\t\t\"id\":   \"column\",\n\t\t\t\"name\": col.Name,\n\t\t\t\"type\": string(col.Type),\n\t\t\t\"op\":   strconv.FormatUint(uint64(col.Options()), 10),\n\t\t})\n\t}\n\treturn routes\n}\n\nfunc (t *Plugin) Call(ctx context.Context, request osquery.ExtensionPluginRequest) osquery.ExtensionResponse {\n\tctx, span := traces.StartSpan(ctx, t.name, \"action\", request[\"action\"], \"table_name\", t.name)\n\tdefer span.End()\n\n\tok := osquery.ExtensionStatus{Code: 0, Message: \"OK\"}\n\tswitch request[\"action\"] {\n\tcase \"generate\":\n\t\tqueryContext, err := parseQueryContext(request[\"context\"])\n\t\tif err != nil {\n\t\t\treturn osquery.ExtensionResponse{\n\t\t\t\tStatus: &osquery.ExtensionStatus{\n\t\t\t\t\tCode:    1,\n\t\t\t\t\tMessage: \"error parsing context JSON: \" + err.Error(),\n\t\t\t\t},\n\t\t\t}\n\t\t}\n\n\t\trows, err := t.generate(ctx, *queryContext)\n\t\tif err != nil {\n\t\t\tspan.RecordError(err)\n\t\t\tspan.SetStatus(codes.Error, err.Error())\n\t\t\treturn osquery.ExtensionResponse{\n\t\t\t\tStatus: &osquery.ExtensionStatus{\n\t\t\t\t\tCode:    1,\n\t\t\t\t\tMessage: \"error generating table: \" + err.Error(),\n\t\t\t\t},\n\t\t\t}\n\t\t}\n\n\t\treturn osquery.ExtensionResponse{\n\t\t\tStatus:   &ok,\n\t\t\tResponse: rows,\n\t\t}\n\n\tcase \"columns\":\n\t\treturn osquery.ExtensionResponse{\n\t\t\tStatus:   &ok,\n\t\t\tResponse: t.Routes(),\n\t\t}\n\n\tdefault:\n\t\treturn osquery.ExtensionResponse{\n\t\t\tStatus: &osquery.ExtensionStatus{\n\t\t\t\tCode:    1,\n\t\t\t\tMessage: \"unknown action: \" + request[\"action\"],\n\t\t\t},\n\t\t}\n\t}\n}\n\nfunc (t *Plugin) Ping() osquery.ExtensionStatus {\n\treturn osquery.ExtensionStatus{Code: 0, Message: \"OK\"}\n}\n\nfunc (t *Plugin) Shutdown() {}\n\n// QueryContext contains the constraints from the WHERE clause of the query,\n// that can optionally be used to optimize the table generation. Note that the\n// osquery SQLite engine will perform the filtering with these constraints, so\n// it is not mandatory that they be used in table generation.\ntype QueryContext struct {\n\t// Constraints is a map from column name to the details of the\n\t// constraints on that column.\n\tConstraints map[string]ConstraintList\n}\n\n// ConstraintList contains the details of the constraints for the given column.\ntype ConstraintList struct {\n\tAffinity    ColumnType\n\tConstraints []Constraint\n}\n\n// Constraint contains both an operator and an expression that are applied as\n// constraints in the query.\ntype Constraint struct {\n\tOperator   Operator\n\tExpression string\n}\n\ntype platformName string\n\nconst (\n\tDarwinPlatform  platformName = \"darwin\"\n\tWindowsPlatform platformName = \"windows\"\n\tLinuxPlatform   platformName = \"linux\"\n)\n\n// Operator is an enum of the osquery operators.\ntype Operator int\n\n// The following operators are defined in osquery tables.h.\nconst (\n\tOperatorEquals              Operator = 2\n\tOperatorGreaterThan                  = 4\n\tOperatorLessThanOrEquals             = 8\n\tOperatorLessThan                     = 16\n\tOperatorGreaterThanOrEquals          = 32\n\tOperatorMatch                        = 64\n\tOperatorLike                         = 65\n\tOperatorGlob                         = 66\n\tOperatorRegexp                       = 67\n\tOperatorUnique                       = 1\n\tOperatorIn                           = 3\n)\n\n// The following types and functions exist for parsing of the queryContext\n// JSON and are not made public.\ntype queryContextJSON struct {\n\tConstraints []constraintListJSON `json:\"constraints\"`\n}\n\ntype constraintListJSON struct {\n\tName     string          `json:\"name\"`\n\tAffinity string          `json:\"affinity\"`\n\tList     json.RawMessage `json:\"list\"`\n}\n\nfunc parseQueryContext(ctxJSON string) (*QueryContext, error) {\n\tvar parsed queryContextJSON\n\n\terr := json.Unmarshal([]byte(ctxJSON), &parsed)\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"unmarshaling context JSON\")\n\t}\n\n\tctx := QueryContext{map[string]ConstraintList{}}\n\tfor _, cList := range parsed.Constraints {\n\t\tconstraints, err := parseConstraintList(cList.List)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tctx.Constraints[cList.Name] = ConstraintList{\n\t\t\tAffinity:    ColumnType(cList.Affinity),\n\t\t\tConstraints: constraints,\n\t\t}\n\t}\n\n\treturn &ctx, nil\n}\n\nfunc parseConstraintList(constraints json.RawMessage) ([]Constraint, error) {\n\tvar str string\n\terr := json.Unmarshal(constraints, &str)\n\tif err == nil {\n\t\t// string indicates empty list\n\t\treturn []Constraint{}, nil\n\t}\n\n\tvar cList []map[string]interface{}\n\terr = json.Unmarshal(constraints, &cList)\n\tif err != nil {\n\t\t// cannot do anything with other types\n\t\treturn nil, errors.Errorf(\"unexpected context list: %s\", string(constraints))\n\t}\n\n\tcl := []Constraint{}\n\tfor _, c := range cList {\n\t\tvar op Operator\n\t\tswitch opVal := c[\"op\"].(type) {\n\t\tcase string: // osquery < 3.0 with stringy types\n\t\t\topInt, err := strconv.Atoi(opVal)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, errors.Errorf(\"parsing operator int: %s\", c[\"op\"])\n\t\t\t}\n\t\t\top = Operator(opInt)\n\t\tcase float64: // osquery > 3.0 with strong types\n\t\t\top = Operator(opVal)\n\t\tdefault:\n\t\t\treturn nil, errors.Errorf(\"cannot parse type %T\", opVal)\n\t\t}\n\n\t\texpr, ok := c[\"expr\"].(string)\n\t\tif !ok {\n\t\t\treturn nil, errors.Errorf(\"expr should be string: %s\", c[\"expr\"])\n\t\t}\n\n\t\tcl = append(cl, Constraint{\n\t\t\tOperator:   op,\n\t\t\tExpression: expr,\n\t\t})\n\t}\n\treturn cl, nil\n}\n"
  },
  {
    "path": "plugin/table/table_test.go",
    "content": "package table\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"testing\"\n\n\t\"github.com/osquery/osquery-go/gen/osquery\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestTablePlugin(t *testing.T) {\n\tvar StatusOK = osquery.ExtensionStatus{Code: 0, Message: \"OK\"}\n\tvar calledQueryCtx QueryContext\n\tplugin := NewPlugin(\n\t\t\"mock\",\n\t\t[]ColumnDefinition{\n\t\t\tTextColumn(\"text\"),\n\t\t\tIntegerColumn(\"integer\"),\n\t\t\tBigIntColumn(\"big_int\"),\n\t\t\tDoubleColumn(\"double\"),\n\t\t},\n\t\tfunc(ctx context.Context, queryCtx QueryContext) ([]map[string]string, error) {\n\t\t\tcalledQueryCtx = queryCtx\n\t\t\treturn []map[string]string{\n\t\t\t\t{\n\t\t\t\t\t\"text\":    \"hello world\",\n\t\t\t\t\t\"integer\": \"123\",\n\t\t\t\t\t\"big_int\": \"-1234567890\",\n\t\t\t\t\t\"double\":  \"3.14159\",\n\t\t\t\t},\n\t\t\t}, nil\n\t\t})\n\n\t// Basic methods\n\tassert.Equal(t, \"table\", plugin.RegistryName())\n\tassert.Equal(t, \"mock\", plugin.Name())\n\tassert.Equal(t, StatusOK, plugin.Ping())\n\tassert.Equal(t, osquery.ExtensionPluginResponse{\n\t\t{\"id\": \"column\", \"name\": \"text\", \"type\": \"TEXT\", \"op\": \"0\"},\n\t\t{\"id\": \"column\", \"name\": \"integer\", \"type\": \"INTEGER\", \"op\": \"0\"},\n\t\t{\"id\": \"column\", \"name\": \"big_int\", \"type\": \"BIGINT\", \"op\": \"0\"},\n\t\t{\"id\": \"column\", \"name\": \"double\", \"type\": \"DOUBLE\", \"op\": \"0\"},\n\t}, plugin.Routes())\n\n\t// Call explicit columns action\n\tresp := plugin.Call(context.Background(), osquery.ExtensionPluginRequest{\"action\": \"columns\"})\n\tassert.Equal(t, &StatusOK, resp.Status)\n\tassert.Equal(t, osquery.ExtensionPluginResponse{\n\t\t{\"id\": \"column\", \"name\": \"text\", \"type\": \"TEXT\", \"op\": \"0\"},\n\t\t{\"id\": \"column\", \"name\": \"integer\", \"type\": \"INTEGER\", \"op\": \"0\"},\n\t\t{\"id\": \"column\", \"name\": \"big_int\", \"type\": \"BIGINT\", \"op\": \"0\"},\n\t\t{\"id\": \"column\", \"name\": \"double\", \"type\": \"DOUBLE\", \"op\": \"0\"},\n\t}, resp.Response)\n\n\t// Call with good action and context\n\tresp = plugin.Call(context.Background(), osquery.ExtensionPluginRequest{\"action\": \"generate\", \"context\": \"{}\"})\n\tassert.Equal(t, QueryContext{map[string]ConstraintList{}}, calledQueryCtx)\n\tassert.Equal(t, &StatusOK, resp.Status)\n\tassert.Equal(t, osquery.ExtensionPluginResponse{\n\t\t{\n\t\t\t\"text\":    \"hello world\",\n\t\t\t\"integer\": \"123\",\n\t\t\t\"big_int\": \"-1234567890\",\n\t\t\t\"double\":  \"3.14159\",\n\t\t},\n\t}, resp.Response)\n}\n\nfunc TestTablePluginErrors(t *testing.T) {\n\tvar called bool\n\tplugin := NewPlugin(\n\t\t\"mock\",\n\t\t[]ColumnDefinition{\n\t\t\tTextColumn(\"text\"),\n\t\t\tIntegerColumn(\"integer\"),\n\t\t\tBigIntColumn(\"big_int\"),\n\t\t\tDoubleColumn(\"double\"),\n\t\t},\n\t\tfunc(ctx context.Context, queryCtx QueryContext) ([]map[string]string, error) {\n\t\t\tcalled = true\n\t\t\treturn nil, errors.New(\"foobar\")\n\t\t},\n\t)\n\n\t// Call with bad actions\n\tassert.Equal(t, int32(1), plugin.Call(context.Background(), osquery.ExtensionPluginRequest{}).Status.Code)\n\tassert.False(t, called)\n\tassert.Equal(t, int32(1), plugin.Call(context.Background(), osquery.ExtensionPluginRequest{\"action\": \"bad\"}).Status.Code)\n\tassert.False(t, called)\n\n\t// Call with good action but generate fails\n\tassert.Equal(t, int32(1), plugin.Call(context.Background(), osquery.ExtensionPluginRequest{\"action\": \"generate\", \"context\": \"{[]}\"}).Status.Code)\n\tassert.False(t, called)\n\n\t// Call with good action but generate fails\n\tresp := plugin.Call(context.Background(), osquery.ExtensionPluginRequest{\"action\": \"generate\", \"context\": \"{}\"})\n\tassert.True(t, called)\n\tassert.Equal(t, int32(1), resp.Status.Code)\n\tassert.Equal(t, \"error generating table: foobar\", resp.Status.Message)\n\n}\n\nfunc TestParseConstraintList(t *testing.T) {\n\tvar testCases = []struct {\n\t\tjson        string\n\t\tconstraints []Constraint\n\t\tshouldErr   bool\n\t}{\n\t\t{\n\t\t\tjson:      \"bad\",\n\t\t\tshouldErr: true,\n\t\t},\n\t\t{\n\t\t\tjson:      `{\"foo\": \"bar\"}`,\n\t\t\tshouldErr: true,\n\t\t},\n\t\t{\n\t\t\tjson:        `\"\"`,\n\t\t\tconstraints: []Constraint{},\n\t\t},\n\t\t{\n\t\t\tjson: `[{\"op\":\"2\",\"expr\":\"foo\"}]`,\n\t\t\tconstraints: []Constraint{\n\t\t\t\tConstraint{OperatorEquals, \"foo\"},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tjson: `[{\"op\":\"4\",\"expr\":\"3\"},{\"op\":\"16\",\"expr\":\"4\"}]`,\n\t\t\tconstraints: []Constraint{\n\t\t\t\tConstraint{OperatorGreaterThan, \"3\"},\n\t\t\t\tConstraint{OperatorLessThan, \"4\"},\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tt := range testCases {\n\t\tt.Run(\"\", func(t *testing.T) {\n\t\t\tconstraints, err := parseConstraintList(json.RawMessage(tt.json))\n\t\t\tif tt.shouldErr {\n\t\t\t\tassert.NotNil(t, err)\n\t\t\t} else {\n\t\t\t\tassert.Equal(t, tt.constraints, constraints)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestParseQueryContext(t *testing.T) {\n\tvar testCases = []struct {\n\t\tjson      string\n\t\tcontext   QueryContext\n\t\tshouldErr bool\n\t}{\n\t\t{\n\t\t\tjson:      \"\",\n\t\t\tshouldErr: true,\n\t\t},\n\t\t{\n\t\t\tjson: `\n{\n  \"constraints\":[\n    {\n      \"name\":\"big_int\",\n      \"list\":\"\",\n      \"affinity\":\"BIGINT\"\n    },\n    {\n      \"name\":\"double\",\n      \"list\":\"\",\n      \"affinity\":\"DOUBLE\"\n    },\n    {\n      \"name\":\"integer\",\n      \"list\":\"\",\n      \"affinity\":\"INTEGER\"\n    },\n    {\n      \"name\":\"text\",\n      \"list\":[\n        {\n          \"op\":\"2\",\n          \"expr\":\"foo\"\n        }\n      ],\n      \"affinity\":\"TEXT\"\n    }\n  ]\n}`,\n\t\t\tcontext: QueryContext{map[string]ConstraintList{\n\t\t\t\t\"big_int\": ConstraintList{ColumnTypeBigInt, []Constraint{}},\n\t\t\t\t\"double\":  ConstraintList{ColumnTypeDouble, []Constraint{}},\n\t\t\t\t\"integer\": ConstraintList{ColumnTypeInteger, []Constraint{}},\n\t\t\t\t\"text\":    ConstraintList{ColumnTypeText, []Constraint{{OperatorEquals, \"foo\"}}},\n\t\t\t}},\n\t\t},\n\t\t{\n\t\t\tjson: `\n{\n  \"constraints\":[\n    {\n      \"name\":\"big_int\",\n      \"list\":\"\",\n      \"affinity\":\"BIGINT\"\n    },\n    {\n      \"name\":\"double\",\n      \"list\":[\n        {\n          \"op\":\"32\",\n          \"expr\":\"3.1\"\n        }\n      ],\n      \"affinity\":\"DOUBLE\"\n    },\n    {\n      \"name\":\"integer\",\n      \"list\":\"\",\n      \"affinity\":\"INTEGER\"\n    },\n    {\n      \"name\":\"text\",\n      \"list\":[\n        {\n          \"op\":\"2\",\n          \"expr\":\"foobar\"\n        }\n      ],\n      \"affinity\":\"TEXT\"\n    }\n  ]\n}\n`,\n\t\t\tcontext: QueryContext{map[string]ConstraintList{\n\t\t\t\t\"big_int\": ConstraintList{ColumnTypeBigInt, []Constraint{}},\n\t\t\t\t\"double\":  ConstraintList{ColumnTypeDouble, []Constraint{{OperatorGreaterThanOrEquals, \"3.1\"}}},\n\t\t\t\t\"integer\": ConstraintList{ColumnTypeInteger, []Constraint{}},\n\t\t\t\t\"text\":    ConstraintList{ColumnTypeText, []Constraint{{OperatorEquals, \"foobar\"}}},\n\t\t\t}},\n\t\t},\n\t}\n\tfor _, tt := range testCases {\n\t\tt.Run(\"\", func(t *testing.T) {\n\t\t\tcontext, err := parseQueryContext(tt.json)\n\t\t\tif tt.shouldErr {\n\t\t\t\tassert.NotNil(t, err)\n\t\t\t} else {\n\t\t\t\tassert.Equal(t, &tt.context, context)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestParseVaryingQueryContexts(t *testing.T) {\n\tvar testCases = []struct {\n\t\tjson            string\n\t\texpectedContext *QueryContext\n\t\tshouldErr       bool\n\t}{\n\t\t{ // Stringy JSON from osquery version < 3\n\t\t\t`{\"constraints\":[{\"name\":\"domain\",\"list\":[{\"op\":\"2\",\"expr\":\"kolide.co\"}],\"affinity\":\"TEXT\"},{\"name\":\"email\",\"list\":\"\",\"affinity\":\"TEXT\"}]}`,\n\t\t\t&QueryContext{\n\t\t\t\tConstraints: map[string]ConstraintList{\n\t\t\t\t\t\"domain\": ConstraintList{Affinity: \"TEXT\", Constraints: []Constraint{Constraint{Operator: OperatorEquals, Expression: \"kolide.co\"}}},\n\t\t\t\t\t\"email\":  ConstraintList{Affinity: \"TEXT\", Constraints: []Constraint{}},\n\t\t\t\t},\n\t\t\t},\n\t\t\tfalse,\n\t\t},\n\t\t{ // Strongly typed JSON from osquery version > 3\n\t\t\t`{\"constraints\":[{\"name\":\"domain\",\"list\":[{\"op\":2,\"expr\":\"kolide.co\"}],\"affinity\":\"TEXT\"},{\"name\":\"email\",\"list\":[],\"affinity\":\"TEXT\"}]}`,\n\t\t\t&QueryContext{\n\t\t\t\tConstraints: map[string]ConstraintList{\n\t\t\t\t\t\"domain\": ConstraintList{Affinity: \"TEXT\", Constraints: []Constraint{Constraint{Operator: OperatorEquals, Expression: \"kolide.co\"}}},\n\t\t\t\t\t\"email\":  ConstraintList{Affinity: \"TEXT\", Constraints: []Constraint{}},\n\t\t\t\t},\n\t\t\t},\n\t\t\tfalse,\n\t\t},\n\t\t{ // Stringy\n\t\t\t`{\"constraints\":[{\"name\":\"path\",\"list\":[{\"op\":\"65\",\"expr\":\"%foobar\"}],\"affinity\":\"TEXT\"},{\"name\":\"query\",\"list\":[{\"op\":\"2\",\"expr\":\"kMDItemFSName = \\\"google*\\\"\"}],\"affinity\":\"TEXT\"}]}`,\n\t\t\t&QueryContext{\n\t\t\t\tConstraints: map[string]ConstraintList{\n\t\t\t\t\t\"path\":  ConstraintList{Affinity: \"TEXT\", Constraints: []Constraint{Constraint{Operator: OperatorLike, Expression: \"%foobar\"}}},\n\t\t\t\t\t\"query\": ConstraintList{Affinity: \"TEXT\", Constraints: []Constraint{Constraint{Operator: OperatorEquals, Expression: \"kMDItemFSName = \\\"google*\\\"\"}}},\n\t\t\t\t},\n\t\t\t},\n\t\t\tfalse,\n\t\t},\n\t\t{ // Strong\n\t\t\t`{\"constraints\":[{\"name\":\"path\",\"list\":[{\"op\":65,\"expr\":\"%foobar\"}],\"affinity\":\"TEXT\"},{\"name\":\"query\",\"list\":[{\"op\":2,\"expr\":\"kMDItemFSName = \\\"google*\\\"\"}],\"affinity\":\"TEXT\"}]}`,\n\t\t\t&QueryContext{\n\t\t\t\tConstraints: map[string]ConstraintList{\n\t\t\t\t\t\"path\":  ConstraintList{Affinity: \"TEXT\", Constraints: []Constraint{Constraint{Operator: OperatorLike, Expression: \"%foobar\"}}},\n\t\t\t\t\t\"query\": ConstraintList{Affinity: \"TEXT\", Constraints: []Constraint{Constraint{Operator: OperatorEquals, Expression: \"kMDItemFSName = \\\"google*\\\"\"}}},\n\t\t\t\t},\n\t\t\t},\n\t\t\tfalse,\n\t\t},\n\n\t\t// Error cases\n\t\t{`{bad json}`, nil, true},\n\t\t{`{\"constraints\":[{\"name\":\"foo\",\"list\":[\"bar\", \"baz\"],\"affinity\":\"TEXT\"}]`, nil, true},\n\t}\n\n\tfor _, tt := range testCases {\n\t\tt.Run(\"\", func(t *testing.T) {\n\t\t\tcontext, err := parseQueryContext(tt.json)\n\t\t\tif tt.shouldErr {\n\t\t\t\trequire.Error(t, err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\trequire.NoError(t, err)\n\n\t\t\tassert.Equal(t, tt.expectedContext, context)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "server.go",
    "content": "package osquery\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/apache/thrift/lib/go/thrift\"\n\n\t\"github.com/osquery/osquery-go/gen/osquery\"\n\t\"github.com/osquery/osquery-go/traces\"\n\t\"github.com/osquery/osquery-go/transport\"\n\t\"github.com/pkg/errors\"\n)\n\ntype OsqueryPlugin interface {\n\t// Name is the name used to refer to the plugin (eg. the name of the\n\t// table the plugin implements).\n\tName() string\n\t// RegistryName is which \"registry\" the plugin should be added to.\n\t// Valid names are [\"config\", \"logger\", \"table\"].\n\tRegistryName() string\n\t// Routes returns the detailed information about the interface exposed\n\t// by the plugin. See the example plugins for samples.\n\tRoutes() osquery.ExtensionPluginResponse\n\t// Ping implements a health check for the plugin. If the plugin is in a\n\t// healthy state, StatusOK should be returned.\n\tPing() osquery.ExtensionStatus\n\t// Call requests the plugin to perform its defined behavior, returning\n\t// a response containing the result.\n\tCall(context.Context, osquery.ExtensionPluginRequest) osquery.ExtensionResponse\n\t// Shutdown alerts the plugin to stop.\n\tShutdown()\n}\n\ntype ExtensionManager interface {\n\tClose()\n\tPing() (*osquery.ExtensionStatus, error)\n\tCall(registry, item string, req osquery.ExtensionPluginRequest) (*osquery.ExtensionResponse, error)\n\tExtensions() (osquery.InternalExtensionList, error)\n\tRegisterExtension(info *osquery.InternalExtensionInfo, registry osquery.ExtensionRegistry) (*osquery.ExtensionStatus, error)\n\tDeregisterExtension(uuid osquery.ExtensionRouteUUID) (*osquery.ExtensionStatus, error)\n\tOptions() (osquery.InternalOptionList, error)\n\tQuery(sql string) (*osquery.ExtensionResponse, error)\n\tGetQueryColumns(sql string) (*osquery.ExtensionResponse, error)\n}\n\nconst defaultTimeout = 1 * time.Second\nconst defaultPingInterval = 5 * time.Second\n\n// ExtensionManagerServer is an implementation of the full ExtensionManager\n// API. Plugins can register with an extension manager, which handles the\n// communication with the osquery process.\ntype ExtensionManagerServer struct {\n\tname                       string\n\tversion                    string\n\tsockPath                   string\n\tserverClient               ExtensionManager\n\tserverClientShouldShutdown bool // Whether to shutdown the client during server shutdown\n\tregistry                   map[string](map[string]OsqueryPlugin)\n\tserver                     thrift.TServer\n\ttransport                  thrift.TServerTransport\n\ttimeout                    time.Duration\n\tpingInterval               time.Duration // How often to ping osquery server\n\tmutex                      sync.Mutex\n\tuuid                       osquery.ExtensionRouteUUID\n\tstarted                    bool // Used to ensure tests wait until the server is actually started\n}\n\n// validRegistryNames contains the allowable RegistryName() values. If a plugin\n// attempts to register with another value, the program will panic.\nvar validRegistryNames = map[string]bool{\n\t\"table\":       true,\n\t\"logger\":      true,\n\t\"config\":      true,\n\t\"distributed\": true,\n}\n\ntype ServerOption func(*ExtensionManagerServer)\n\nfunc ExtensionVersion(version string) ServerOption {\n\treturn func(s *ExtensionManagerServer) {\n\t\ts.version = version\n\t}\n}\n\nfunc ServerTimeout(timeout time.Duration) ServerOption {\n\treturn func(s *ExtensionManagerServer) {\n\t\ts.timeout = timeout\n\t}\n}\n\nfunc ServerPingInterval(interval time.Duration) ServerOption {\n\treturn func(s *ExtensionManagerServer) {\n\t\ts.pingInterval = interval\n\t}\n}\n\n// ServerSideConnectivityCheckInterval Sets a thrift package variable for the ticker\n// interval used by connectivity check in thrift compiled TProcessorFunc implementations.\n// See the thrift docs for more information\nfunc ServerConnectivityCheckInterval(interval time.Duration) ServerOption {\n\treturn func(s *ExtensionManagerServer) {\n\t\ts.mutex.Lock()\n\t\tdefer s.mutex.Unlock()\n\n\t\tthrift.ServerConnectivityCheckInterval = interval\n\t}\n}\n\n// WithClient sets the server to use an existing ExtensionManagerClient\n// instead of creating a new one.\nfunc WithClient(client ExtensionManager) ServerOption {\n\treturn func(s *ExtensionManagerServer) {\n\t\ts.serverClient = client\n\t}\n}\n\n// MaxSocketPathCharacters is set to 97 because a \".12345\" uuid is added to the socket down stream\n// if the provided socket is greater than 97 we may exceed the limit of 103 (104 causes an error)\n// why 103 limit? https://unix.stackexchange.com/questions/367008/why-is-socket-path-length-limited-to-a-hundred-chars\nconst MaxSocketPathCharacters = 97\n\n// NewExtensionManagerServer creates a new extension management server\n// communicating with osquery over the socket at the provided path. If\n// resolving the address or connecting to the socket fails, this function will\n// error.\nfunc NewExtensionManagerServer(name string, sockPath string, opts ...ServerOption) (*ExtensionManagerServer, error) {\n\n\tif len(sockPath) > MaxSocketPathCharacters {\n\t\treturn nil, errors.Errorf(\"socket path %s (%d characters) exceeded the maximum socket path character length of %d\", sockPath, len(sockPath), MaxSocketPathCharacters)\n\t}\n\n\t// Initialize nested registry maps\n\tregistry := make(map[string](map[string]OsqueryPlugin))\n\tfor reg := range validRegistryNames {\n\t\tregistry[reg] = make(map[string]OsqueryPlugin)\n\t}\n\n\tmanager := &ExtensionManagerServer{\n\t\tname:         name,\n\t\tsockPath:     sockPath,\n\t\tregistry:     registry,\n\t\ttimeout:      defaultTimeout,\n\t\tpingInterval: defaultPingInterval,\n\t}\n\n\tfor _, opt := range opts {\n\t\topt(manager)\n\t}\n\n\tif manager.serverClient == nil {\n\t\tserverClient, err := NewClient(sockPath, manager.timeout)\n\t\tif err != nil {\n\t\t\tif serverClient != nil {\n\t\t\t\tserverClient.Close()\n\t\t\t}\n\t\t\treturn nil, err\n\t\t}\n\t\tmanager.serverClient = serverClient\n\t\tmanager.serverClientShouldShutdown = true\n\t}\n\n\treturn manager, nil\n}\n\n// RegisterPlugin adds one or more OsqueryPlugins to this extension manager.\nfunc (s *ExtensionManagerServer) RegisterPlugin(plugins ...OsqueryPlugin) {\n\ts.mutex.Lock()\n\tdefer s.mutex.Unlock()\n\tfor _, plugin := range plugins {\n\t\tif !validRegistryNames[plugin.RegistryName()] {\n\t\t\tpanic(\"invalid registry name: \" + plugin.RegistryName())\n\t\t}\n\t\ts.registry[plugin.RegistryName()][plugin.Name()] = plugin\n\t}\n}\n\nfunc (s *ExtensionManagerServer) genRegistry() osquery.ExtensionRegistry {\n\tregistry := osquery.ExtensionRegistry{}\n\tfor regName := range s.registry {\n\t\tregistry[regName] = osquery.ExtensionRouteTable{}\n\t\tfor _, plugin := range s.registry[regName] {\n\t\t\tregistry[regName][plugin.Name()] = plugin.Routes()\n\t\t}\n\t}\n\treturn registry\n}\n\n// Start registers the extension plugins and begins listening on a unix socket\n// for requests from the osquery process. All plugins should be registered with\n// RegisterPlugin() before calling Start().\nfunc (s *ExtensionManagerServer) Start() error {\n\tvar server thrift.TServer\n\terr := func() error {\n\t\ts.mutex.Lock()\n\t\tdefer s.mutex.Unlock()\n\t\t// check after the lock the serverClient is present. It could have gone away on very short restart loops\n\t\tif s.serverClient == nil {\n\t\t\treturn errors.New(\"cannot start, shutdown in progress\")\n\t\t}\n\t\tregistry := s.genRegistry()\n\n\t\tstat, err := s.serverClient.RegisterExtension(\n\t\t\t&osquery.InternalExtensionInfo{\n\t\t\t\tName:    s.name,\n\t\t\t\tVersion: s.version,\n\t\t\t},\n\t\t\tregistry,\n\t\t)\n\n\t\tif err != nil {\n\t\t\treturn errors.Wrap(err, \"registering extension\")\n\t\t}\n\t\tif stat.Code != 0 {\n\t\t\treturn errors.Errorf(\"status %d registering extension: %s\", stat.Code, stat.Message)\n\t\t}\n\t\ts.uuid = stat.UUID\n\n\t\tlistenPath := fmt.Sprintf(\"%s.%d\", s.sockPath, stat.UUID)\n\n\t\tprocessor := osquery.NewExtensionProcessor(s)\n\n\t\ts.transport, err = transport.OpenServer(listenPath, s.timeout)\n\t\tif err != nil {\n\t\t\topenError := errors.Wrapf(err, \"opening server socket (%s)\", listenPath)\n\t\t\t_, err = s.serverClient.DeregisterExtension(stat.UUID)\n\t\t\tif err != nil {\n\t\t\t\treturn errors.Wrapf(err, \"deregistering extension - follows %s\", openError.Error())\n\t\t\t}\n\t\t\treturn openError\n\t\t}\n\n\t\ts.server = thrift.NewTSimpleServer2(processor, s.transport)\n\t\tserver = s.server\n\n\t\ts.started = true\n\n\t\treturn nil\n\t}()\n\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn server.Serve()\n}\n\n// Run starts the extension manager and runs until osquery calls for a shutdown\n// or the osquery instance goes away.\nfunc (s *ExtensionManagerServer) Run() error {\n\terrc := make(chan error)\n\tgo func() {\n\t\terrc <- s.Start()\n\t}()\n\n\t// Watch for the osquery process going away. If so, initiate shutdown.\n\tgo func() {\n\t\tfor {\n\t\t\ttime.Sleep(s.pingInterval)\n\n\t\t\ts.mutex.Lock()\n\t\t\tserverClient := s.serverClient\n\t\t\ts.mutex.Unlock()\n\n\t\t\t// can't ping if s.Shutdown has already happened\n\t\t\tif serverClient == nil {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tstatus, err := serverClient.Ping()\n\t\t\tif err != nil {\n\t\t\t\terrc <- errors.Wrap(err, \"extension ping failed\")\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tif status.Code != 0 {\n\t\t\t\terrc <- errors.Errorf(\"ping returned status %d\", status.Code)\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}()\n\n\terr := <-errc\n\t_ = s.Shutdown(context.Background())\n\treturn err\n}\n\n// Ping implements the basic health check.\nfunc (s *ExtensionManagerServer) Ping(ctx context.Context) (*osquery.ExtensionStatus, error) {\n\treturn &osquery.ExtensionStatus{Code: 0, Message: \"OK\"}, nil\n}\n\n// Call routes a call from the osquery process to the appropriate registered\n// plugin.\nfunc (s *ExtensionManagerServer) Call(ctx context.Context, registry string, item string, request osquery.ExtensionPluginRequest) (*osquery.ExtensionResponse, error) {\n\tctx, span := traces.StartSpan(ctx, \"ExtensionManagerServer.Call\",\n\t\t\"registry\", registry,\n\t\t\"item\", item,\n\t)\n\tdefer span.End()\n\n\tsubreg, ok := s.registry[registry]\n\tif !ok {\n\t\treturn &osquery.ExtensionResponse{\n\t\t\tStatus: &osquery.ExtensionStatus{\n\t\t\t\tCode:    1,\n\t\t\t\tMessage: \"Unknown registry: \" + registry,\n\t\t\t},\n\t\t}, nil\n\t}\n\n\tplugin, ok := subreg[item]\n\tif !ok {\n\t\treturn &osquery.ExtensionResponse{\n\t\t\tStatus: &osquery.ExtensionStatus{\n\t\t\t\tCode:    1,\n\t\t\t\tMessage: \"Unknown registry item: \" + item,\n\t\t\t},\n\t\t}, nil\n\t}\n\n\tresponse := plugin.Call(ctx, request)\n\treturn &response, nil\n}\n\n// Shutdown deregisters the extension, stops the server and closes all sockets.\nfunc (s *ExtensionManagerServer) Shutdown(ctx context.Context) (err error) {\n\ts.mutex.Lock()\n\tdefer s.mutex.Unlock()\n\n\tif s.serverClient != nil {\n\t\tvar stat *osquery.ExtensionStatus\n\t\tstat, err = s.serverClient.DeregisterExtension(s.uuid)\n\t\terr = errors.Wrap(err, \"deregistering extension\")\n\t\tif err == nil && stat.Code != 0 {\n\t\t\terr = errors.Errorf(\"status %d deregistering extension: %s\", stat.Code, stat.Message)\n\t\t}\n\t}\n\n\tif s.server != nil {\n\t\tserver := s.server\n\t\ts.server = nil\n\t\t// Stop the server asynchronously so that the current request\n\t\t// can complete. Otherwise, this is vulnerable to deadlock if a\n\t\t// shutdown request is being processed when Shutdown is\n\t\t// explicitly called.\n\t\tgo func() {\n\t\t\tserver.Stop()\n\t\t}()\n\t}\n\n\t// Shutdown the client, if appropriate\n\tif s.serverClientShouldShutdown && s.serverClient != nil {\n\t\ts.serverClient.Close()\n\t\ts.serverClient = nil\n\t}\n\n\treturn\n}\n\n// Useful for testing\nfunc (s *ExtensionManagerServer) waitStarted() {\n\tfor {\n\t\ts.mutex.Lock()\n\t\tstarted := s.started\n\t\ts.mutex.Unlock()\n\t\tif started {\n\t\t\ttime.Sleep(10 * time.Millisecond)\n\t\t\tbreak\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "server_test.go",
    "content": "package osquery\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"net\"\n\t\"os\"\n\t\"runtime/pprof\"\n\t\"strings\"\n\t\"sync\"\n\t\"syscall\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/apache/thrift/lib/go/thrift\"\n\t\"github.com/osquery/osquery-go/gen/osquery\"\n\t\"github.com/osquery/osquery-go/plugin/logger\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\n// Verify that an error in server.Start will return an error instead of deadlock.\nfunc TestNoDeadlockOnError(t *testing.T) {\n\tregistry := make(map[string](map[string]OsqueryPlugin))\n\tfor reg := range validRegistryNames {\n\t\tregistry[reg] = make(map[string]OsqueryPlugin)\n\t}\n\tmut := sync.Mutex{}\n\tmock := &MockExtensionManager{\n\t\tRegisterExtensionFunc: func(info *osquery.InternalExtensionInfo, registry osquery.ExtensionRegistry) (*osquery.ExtensionStatus, error) {\n\t\t\tmut.Lock()\n\t\t\tdefer mut.Unlock()\n\t\t\treturn nil, errors.New(\"boom!\")\n\t\t},\n\t\tPingFunc: func() (*osquery.ExtensionStatus, error) {\n\t\t\treturn &osquery.ExtensionStatus{}, nil\n\t\t},\n\t\tDeRegisterExtensionFunc: func(uuid osquery.ExtensionRouteUUID) (*osquery.ExtensionStatus, error) {\n\t\t\treturn &osquery.ExtensionStatus{}, nil\n\t\t},\n\t\tCloseFunc: func() {},\n\t}\n\tserver := &ExtensionManagerServer{\n\t\tserverClient:               mock,\n\t\tregistry:                   registry,\n\t\tserverClientShouldShutdown: true,\n\t}\n\n\tlog := func(ctx context.Context, typ logger.LogType, logText string) error {\n\t\tfmt.Printf(\"%s: %s\\n\", typ, logText)\n\t\treturn nil\n\t}\n\tserver.RegisterPlugin(logger.NewPlugin(\"testLogger\", log))\n\n\terr := server.Run()\n\tassert.Error(t, err)\n\tmut.Lock()\n\tdefer mut.Unlock()\n\tassert.True(t, mock.RegisterExtensionFuncInvoked)\n}\n\n// Ensure that the extension server will shutdown and return if the osquery\n// instance it is talking to stops responding to pings.\nfunc TestShutdownWhenPingFails(t *testing.T) {\n\ttempPath, err := ioutil.TempFile(\"\", \"\")\n\trequire.Nil(t, err)\n\tdefer os.Remove(tempPath.Name())\n\n\tregistry := make(map[string](map[string]OsqueryPlugin))\n\tfor reg := range validRegistryNames {\n\t\tregistry[reg] = make(map[string]OsqueryPlugin)\n\t}\n\tmock := &MockExtensionManager{\n\t\tRegisterExtensionFunc: func(info *osquery.InternalExtensionInfo, registry osquery.ExtensionRegistry) (*osquery.ExtensionStatus, error) {\n\t\t\treturn &osquery.ExtensionStatus{}, nil\n\t\t},\n\t\tPingFunc: func() (*osquery.ExtensionStatus, error) {\n\t\t\t// As if the socket was closed\n\t\t\treturn nil, syscall.EPIPE\n\t\t},\n\t\tDeRegisterExtensionFunc: func(uuid osquery.ExtensionRouteUUID) (*osquery.ExtensionStatus, error) {\n\t\t\treturn &osquery.ExtensionStatus{}, nil\n\t\t},\n\t\tCloseFunc: func() {},\n\t}\n\tserver := &ExtensionManagerServer{\n\t\tserverClient:               mock,\n\t\tregistry:                   registry,\n\t\tserverClientShouldShutdown: true,\n\t\tpingInterval:               1 * time.Second,\n\t\tsockPath:                   tempPath.Name(),\n\t}\n\n\terr = server.Run()\n\tassert.Error(t, err)\n\tassert.Contains(t, err.Error(), \"broken pipe\")\n\tassert.True(t, mock.DeRegisterExtensionFuncInvoked)\n\tassert.True(t, mock.CloseFuncInvoked)\n}\n\n// How many parallel tests to run (because sync issues do not occur on every\n// run, this maximizes our chances of seeing any issue by quickly executing\n// many runs of the test).\nconst parallelTestShutdownDeadlock = 20\n\nfunc TestShutdownDeadlock(t *testing.T) {\n\tfor i := 0; i < parallelTestShutdownDeadlock; i++ {\n\t\ti := i\n\t\tt.Run(\"\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\ttestShutdownDeadlock(t, i)\n\t\t})\n\t}\n}\n\nfunc testShutdownDeadlock(t *testing.T, uuid int) {\n\ttempPath, err := ioutil.TempFile(\"\", \"\")\n\trequire.Nil(t, err)\n\tdefer os.Remove(tempPath.Name())\n\n\tretUUID := osquery.ExtensionRouteUUID(uuid)\n\tmock := &MockExtensionManager{\n\t\tRegisterExtensionFunc: func(info *osquery.InternalExtensionInfo, registry osquery.ExtensionRegistry) (*osquery.ExtensionStatus, error) {\n\t\t\treturn &osquery.ExtensionStatus{Code: 0, UUID: retUUID}, nil\n\t\t},\n\t\tDeRegisterExtensionFunc: func(uuid osquery.ExtensionRouteUUID) (*osquery.ExtensionStatus, error) {\n\t\t\treturn &osquery.ExtensionStatus{}, nil\n\t\t},\n\t\tCloseFunc: func() {},\n\t}\n\tserver := ExtensionManagerServer{\n\t\tserverClient:               mock,\n\t\tsockPath:                   tempPath.Name(),\n\t\ttimeout:                    defaultTimeout,\n\t\tserverClientShouldShutdown: true,\n\t}\n\n\tvar wait sync.WaitGroup\n\n\tgo func() {\n\t\t// We do not wait for this routine to finish because thrift.TServer.Serve\n\t\t// seems to sometimes hang after shutdowns. (This test is just testing\n\t\t// the Shutdown doesn't hang.)\n\t\terr := server.Start()\n\t\trequire.NoError(t, err)\n\t}()\n\n\t// Wait for server to be set up\n\tserver.waitStarted()\n\n\t// Create a raw client to access the shutdown method that is not\n\t// usually exposed.\n\tlistenPath := fmt.Sprintf(\"%s.%d\", tempPath.Name(), retUUID)\n\taddr, err := net.ResolveUnixAddr(\"unix\", listenPath)\n\trequire.Nil(t, err)\n\ttimeout := 500 * time.Millisecond\n\topened := false\n\tattempt := 0\n\tvar transport *thrift.TSocket\n\tfor !opened && attempt < 10 {\n\t\ttransport = thrift.NewTSocketFromAddrTimeout(addr, timeout, timeout)\n\t\terr = transport.Open()\n\t\tattempt++\n\t\tif err != nil {\n\t\t\ttime.Sleep(1 * time.Second)\n\t\t} else {\n\t\t\topened = true\n\t\t}\n\t}\n\trequire.NoError(t, err)\n\tclient := osquery.NewExtensionManagerClientFactory(transport,\n\t\tthrift.NewTBinaryProtocolFactoryDefault())\n\n\t// Simultaneously call shutdown through a request from the client and\n\t// directly on the server object.\n\twait.Add(1)\n\tgo func() {\n\t\tdefer wait.Done()\n\t\tclient.Shutdown(context.Background())\n\t}()\n\n\twait.Add(1)\n\tgo func() {\n\t\tdefer wait.Done()\n\t\terr = server.Shutdown(context.Background())\n\t\trequire.NoError(t, err)\n\t}()\n\n\t// Track whether shutdown completed\n\tcompleted := make(chan struct{})\n\tgo func() {\n\t\twait.Wait()\n\t\tclose(completed)\n\t}()\n\n\t// either indicate successful shutdown, or fatal the test because it\n\t// hung\n\tselect {\n\tcase <-completed:\n\t\t// Success. Do nothing.\n\tcase <-time.After(10 * time.Second):\n\t\tpprof.Lookup(\"goroutine\").WriteTo(os.Stdout, 1)\n\t\tt.Fatal(\"hung on shutdown\")\n\t}\n}\n\nfunc TestShutdownBasic(t *testing.T) {\n\tdir := t.TempDir()\n\n\ttempPath := func() string {\n\t\ttmp, err := os.CreateTemp(dir, \"\")\n\t\trequire.NoError(t, err)\n\t\treturn tmp.Name()\n\t}\n\n\tretUUID := osquery.ExtensionRouteUUID(0)\n\tmock := &MockExtensionManager{\n\t\tRegisterExtensionFunc: func(info *osquery.InternalExtensionInfo, registry osquery.ExtensionRegistry) (*osquery.ExtensionStatus, error) {\n\t\t\treturn &osquery.ExtensionStatus{Code: 0, UUID: retUUID}, nil\n\t\t},\n\t\tDeRegisterExtensionFunc: func(uuid osquery.ExtensionRouteUUID) (*osquery.ExtensionStatus, error) {\n\t\t\treturn &osquery.ExtensionStatus{}, nil\n\t\t},\n\t\tCloseFunc: func() {},\n\t}\n\n\tfor _, server := range []*ExtensionManagerServer{\n\t\t// Create the extension manager without using NewExtensionManagerServer.\n\t\t{serverClient: mock, sockPath: tempPath()},\n\t\t// Create the extension manager using ExtensionManagerServer.\n\t\t{serverClient: mock, sockPath: tempPath(), serverClientShouldShutdown: true},\n\t} {\n\t\tcompleted := make(chan struct{})\n\t\tgo func() {\n\t\t\terr := server.Start()\n\t\t\trequire.NoError(t, err)\n\t\t\tclose(completed)\n\t\t}()\n\n\t\tserver.waitStarted()\n\n\t\terr := server.Shutdown(context.Background())\n\t\trequire.NoError(t, err)\n\n\t\t// Test that server.Shutdown is idempotent.\n\t\terr = server.Shutdown(context.Background())\n\t\trequire.NoError(t, err)\n\n\t\t// Either indicate successful shutdown, or fatal the test because it\n\t\t// hung\n\t\tselect {\n\t\tcase <-completed:\n\t\t\t// Success. Do nothing.\n\t\tcase <-time.After(5 * time.Second):\n\t\t\tt.Fatal(\"hung on shutdown\")\n\t\t}\n\n\t}\n}\n\nfunc TestNewExtensionManagerServer(t *testing.T) {\n\tt.Parallel()\n\n\ttype args struct {\n\t\tname     string\n\t\tsockPath string\n\t\topts     []ServerOption\n\t}\n\ttests := []struct {\n\t\tname           string\n\t\targs           args\n\t\twant           *ExtensionManagerServer\n\t\terrContainsStr string\n\t}{\n\t\t{\n\t\t\tname: \"socket path too long\",\n\t\t\targs: args{\n\t\t\t\tname:     \"socket_path_too_long\",\n\t\t\t\tsockPath: strings.Repeat(\"a\", MaxSocketPathCharacters+1),\n\t\t\t\topts:     []ServerOption{},\n\t\t\t},\n\t\t\terrContainsStr: \"exceeded the maximum socket path character length\",\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\ttt := tt\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tgot, err := NewExtensionManagerServer(tt.args.name, tt.args.sockPath, tt.args.opts...)\n\t\t\tif tt.errContainsStr != \"\" {\n\t\t\t\trequire.Error(t, err)\n\t\t\t\trequire.Contains(t, err.Error(), tt.errContainsStr)\n\t\t\t} else {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.NotNil(t, got)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "traces/traces.go",
    "content": "// Package traces allows for instrumenting osquery-go with OpenTelemetry traces.\n// Unless the consuming application specifically configures a trace exporter, all tracing is a no-op.\npackage traces\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"runtime/debug\"\n\n\t\"go.opentelemetry.io/otel\"\n\t\"go.opentelemetry.io/otel/attribute\"\n\t\"go.opentelemetry.io/otel/trace\"\n)\n\nconst instrumentationPkg = \"github.com/osquery/osquery-go\"\n\nvar (\n\tinternalVersion string // provides the instrumentation version for attribute `otel.scope.version`\n\ttracerProvider  trace.TracerProvider\n)\n\n// init sets `internalVersion` and a default tracer provider.\nfunc init() {\n\t// By default, use the global tracer provider, which is a no-op provider.\n\ttracerProvider = otel.GetTracerProvider()\n\n\t// Look through build info to determine the current version of the osquery-go package.\n\tif info, ok := debug.ReadBuildInfo(); ok {\n\t\tfor _, dep := range info.Deps {\n\t\t\tif dep == nil {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif dep.Path == instrumentationPkg {\n\t\t\t\tinternalVersion = dep.Version\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n\n\t// Couldn't get the version from runtime build info -- save 0.0.0,\n\t// which is the current osquery-go version.\n\tinternalVersion = \"0.0.0\"\n}\n\n// SetTracerProvider allows consuming libraries to set a custom/non-global tracer provider.\nfunc SetTracerProvider(tp trace.TracerProvider) {\n\ttracerProvider = tp\n}\n\n// OsqueryGoTracer provides a tracer with a standardized name and version.\n// It should be used to start a span that requires `SpanStartOption`s that are\n// not supported by `StartSpan` below -- i.e., any `SpanStartOption` besides\n// `WithAttributes`.\nfunc OsqueryGoTracer() trace.Tracer {\n\treturn tracerProvider.Tracer(instrumentationPkg, trace.WithInstrumentationVersion(internalVersion))\n}\n\n// StartSpan is a wrapper around trace.Tracer.Start that simplifies passing in span attributes.\n// `keyVals` should be a list of pairs, where the first in the pair is a string representing\n// the attribute key and the second in the pair is the attribute value.\n// The caller is always responsible for ending the returned span.\n// Any spans requiring more specific configuration can be created manually via OsqueryGoTracer().Start.\nfunc StartSpan(ctx context.Context, spanName string, keyVals ...string) (context.Context, trace.Span) {\n\tattrs := make([]attribute.KeyValue, 0)\n\n\tfor i := 0; i < len(keyVals); i += 2 {\n\t\t// Ensure all attributes are appropriately namespaced\n\t\tkey := fmt.Sprintf(\"osquery-go.%s\", keyVals[i])\n\t\tattrs = append(attrs, attribute.String(key, keyVals[i+1]))\n\t}\n\n\topts := []trace.SpanStartOption{trace.WithAttributes(attrs...)}\n\n\treturn OsqueryGoTracer().Start(ctx, spanName, opts...)\n}\n"
  },
  {
    "path": "traces/traces_test.go",
    "content": "package traces\n\nimport (\n\t\"context\"\n\t\"sync\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestTraceInit(t *testing.T) {\n\tt.Parallel()\n\n\t// Start several spans in quick succession to confirm there's no data race on setting `internalVersion`\n\tvar wg sync.WaitGroup\n\tfor i := 0; i < 5; i += 1 {\n\t\twg.Add(1)\n\t\tgo func() {\n\t\t\tdefer wg.Done()\n\t\t\t_, span := StartSpan(context.TODO(), \"TestSpan\")\n\t\t\tspan.End()\n\t\t}()\n\t}\n\n\twg.Wait()\n\tassert.NotEmpty(t, internalVersion, \"internal version should have been set\")\n}\n"
  },
  {
    "path": "transport/doc.go",
    "content": "// Package transport provides Thrift TTransport and TServerTransport\n// implementations for use on mac/linux (TSocket/TServerSocket) and Windows\n// (custom named pipe implementation).\npackage transport\n"
  },
  {
    "path": "transport/transport.go",
    "content": "//go:build !windows\n// +build !windows\n\npackage transport\n\nimport (\n\t\"context\"\n\t\"net\"\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/apache/thrift/lib/go/thrift\"\n\t\"github.com/pkg/errors\"\n)\n\n// Open opens the unix domain socket with the provided path and timeout,\n// returning a TTransport.\nfunc Open(sockPath string, timeout time.Duration) (*thrift.TSocket, error) {\n\taddr, err := net.ResolveUnixAddr(\"unix\", sockPath)\n\tif err != nil {\n\t\treturn nil, errors.Wrapf(err, \"resolving socket path '%s'\", sockPath)\n\t}\n\n\t// the timeout parameter is passed to thrift, which passes it to net.DialTimeout\n\t// but it looks like net.DialTimeout ignores timeouts for unix socket and immediately returns an error\n\t// waitForSocket will loop every 200ms to stat the socket path,\n\t// or until the timeout value passes, similar to the C++ and python implementations.\n\tif err := waitForSocket(sockPath, timeout); err != nil {\n\t\treturn nil, errors.Wrapf(err, \"waiting for unix socket to be available: %s\", sockPath)\n\t}\n\n\ttrans := thrift.NewTSocketFromAddrTimeout(addr, timeout, timeout)\n\tif err := trans.Open(); err != nil {\n\t\treturn nil, errors.Wrap(err, \"opening socket transport\")\n\t}\n\n\treturn trans, nil\n}\n\nfunc OpenServer(listenPath string, timeout time.Duration) (*thrift.TServerSocket, error) {\n\taddr, err := net.ResolveUnixAddr(\"unix\", listenPath)\n\tif err != nil {\n\t\treturn nil, errors.Wrapf(err, \"resolving addr (%s)\", addr)\n\t}\n\n\treturn thrift.NewTServerSocketFromAddrTimeout(addr, 0), nil\n}\n\nfunc waitForSocket(sockPath string, timeout time.Duration) error {\n\tticker := time.NewTicker(200 * time.Millisecond)\n\tdefer ticker.Stop()\n\tctx, cancel := context.WithTimeout(context.Background(), timeout)\n\tdefer cancel()\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn ctx.Err()\n\t\tcase <-ticker.C:\n\t\t\tif _, err := os.Stat(sockPath); err == nil {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "transport/transport_windows.go",
    "content": "//go:build windows\n// +build windows\n\npackage transport\n\nimport (\n\t\"net\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/Microsoft/go-winio\"\n\t\"github.com/pkg/errors\"\n\n\t\"github.com/apache/thrift/lib/go/thrift\"\n)\n\n// Open opens the named pipe with the provided path and timeout,\n// returning a TTransport.\nfunc Open(path string, timeout time.Duration) (*thrift.TSocket, error) {\n\tconn, err := winio.DialPipe(path, &timeout)\n\tif err != nil {\n\t\treturn nil, errors.Wrapf(err, \"dialing pipe '%s'\", path)\n\t}\n\treturn thrift.NewTSocketFromConnTimeout(conn, timeout), nil\n}\n\nfunc OpenServer(pipePath string, timeout time.Duration) (*TServerPipe, error) {\n\treturn NewTServerPipeTimeout(pipePath, timeout)\n}\n\n// TServerPipe is a windows named pipe implementation of the\ntype TServerPipe struct {\n\tlistener      net.Listener\n\tpipePath      string\n\tclientTimeout time.Duration\n\n\t// Protects the interrupted value to make it thread safe.\n\tmu          sync.RWMutex\n\tinterrupted bool\n}\n\nfunc NewTServerPipeTimeout(pipePath string, clientTimeout time.Duration) (*TServerPipe, error) {\n\treturn &TServerPipe{pipePath: pipePath, clientTimeout: clientTimeout}, nil\n}\n\nfunc (p *TServerPipe) Listen() error {\n\tp.mu.Lock()\n\tdefer p.mu.Unlock()\n\n\tif p.IsListening() {\n\t\treturn nil\n\t}\n\n\tl, err := winio.ListenPipe(p.pipePath, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tp.listener = l\n\treturn nil\n}\n\n// IsListening returns whether the server transport is currently listening.\nfunc (p *TServerPipe) IsListening() bool {\n\treturn p.listener != nil\n}\n\n// Accept wraps the standard net.Listener accept to return a thrift.TTransport.\nfunc (p *TServerPipe) Accept() (thrift.TTransport, error) {\n\tp.mu.RLock()\n\tinterrupted := p.interrupted\n\tlistener := p.listener\n\tp.mu.RUnlock()\n\n\tif interrupted {\n\t\treturn nil, errors.New(\"transport interrupted\")\n\t}\n\n\tconn, err := listener.Accept()\n\tif err != nil {\n\t\treturn nil, thrift.NewTTransportExceptionFromError(err)\n\t}\n\treturn thrift.NewTSocketFromConnTimeout(conn, p.clientTimeout), nil\n}\n\nfunc (p *TServerPipe) Close() error {\n\tdefer func() {\n\t\tp.listener = nil\n\t}()\n\tif p.IsListening() {\n\t\treturn p.listener.Close()\n\t}\n\treturn nil\n}\n\n// Interrupt is a noop for this implementation\nfunc (p *TServerPipe) Interrupt() error {\n\tp.mu.Lock()\n\tdefer p.mu.Unlock()\n\n\tp.interrupted = true\n\tp.Close()\n\n\treturn nil\n}\n"
  }
]