{"action":"created","issue":{"url":"https://api.github.com/repos/threefoldtech/0-stor/issues/9","repository_url":"https://api.github.com/repos/threefoldtech/0-stor","labels_url":"https://api.github.com/repos/threefoldtech/0-stor/issues/9/labels{/name}","comments_url":"https://api.github.com/repos/threefoldtech/0-stor/issues/9/comments","events_url":"https://api.github.com/repos/threefoldtech/0-stor/issues/9/events","html_url":"https://github.com/threefoldtech/0-stor/issues/9","id":346608837,"node_id":"MDU6SXNzdWUzNDY2MDg4Mzc=","number":9,"title":"add Golang client for the 0-stor daemon","user":{"login":"rkhamis","id":8425762,"node_id":"MDQ6VXNlcjg0MjU3NjI=","avatar_url":"https://avatars1.githubusercontent.com/u/8425762?v=4","gravatar_id":"","url":"https://api.github.com/users/rkhamis","html_url":"https://github.com/rkhamis","followers_url":"https://api.github.com/users/rkhamis/followers","following_url":"https://api.github.com/users/rkhamis/following{/other_user}","gists_url":"https://api.github.com/users/rkhamis/gists{/gist_id}","starred_url":"https://api.github.com/users/rkhamis/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rkhamis/subscriptions","organizations_url":"https://api.github.com/users/rkhamis/orgs","repos_url":"https://api.github.com/users/rkhamis/repos","events_url":"https://api.github.com/users/rkhamis/events{/privacy}","received_events_url":"https://api.github.com/users/rkhamis/received_events","type":"User","site_admin":false},"labels":[{"id":1011507443,"node_id":"MDU6TGFiZWwxMDExNTA3NDQz","url":"https://api.github.com/repos/threefoldtech/0-stor/labels/type_feature","name":"type_feature","color":"fef2c0","default":false}],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":{"url":"https://api.github.com/repos/threefoldtech/0-stor/milestones/1","html_url":"https://github.com/threefoldtech/0-stor/milestone/1","labels_url":"https://api.github.com/repos/threefoldtech/0-stor/milestones/1/labels","id":3539334,"node_id":"MDk6TWlsZXN0b25lMzUzOTMzNA==","number":1,"title":"Roadmap","description":"Feature we plan to implement","creator":{"login":"rkhamis","id":8425762,"node_id":"MDQ6VXNlcjg0MjU3NjI=","avatar_url":"https://avatars1.githubusercontent.com/u/8425762?v=4","gravatar_id":"","url":"https://api.github.com/users/rkhamis","html_url":"https://github.com/rkhamis","followers_url":"https://api.github.com/users/rkhamis/followers","following_url":"https://api.github.com/users/rkhamis/following{/other_user}","gists_url":"https://api.github.com/users/rkhamis/gists{/gist_id}","starred_url":"https://api.github.com/users/rkhamis/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rkhamis/subscriptions","organizations_url":"https://api.github.com/users/rkhamis/orgs","repos_url":"https://api.github.com/users/rkhamis/repos","events_url":"https://api.github.com/users/rkhamis/events{/privacy}","received_events_url":"https://api.github.com/users/rkhamis/received_events","type":"User","site_admin":false},"open_issues":5,"closed_issues":0,"state":"open","created_at":"2018-08-01T13:48:10Z","updated_at":"2018-08-01T13:50:16Z","due_on":null,"closed_at":null},"comments":0,"created_at":"2018-08-01T13:50:16Z","updated_at":"2018-08-01T13:50:18Z","closed_at":null,"author_association":"NONE","body":"*Issue migrated from [https://api.github.com/repos/zero-os/0-stor/issues/447](), opened by @GlenDC*\n\nNow that the daemon is implemented, according to #68, we can provide \"dumb\" clients for all kind of languages, including Golang.\r\n\r\nOn the client side there are in fact 4 clients that we could support, and they would more or less have the following interface (note that they should probably just be structs, but I'm defining them here as interfaces as its easier for a 'spec'\"):\r\n\r\n```golang\r\ntype Client interface {\r\n    Write(key, data []byte) (*metatypes.Metadata, error)\r\n    WriteFile(key []byte, filePath string) (*metatypes.Metadata, error)\r\n    WriteStream(key []byte, io.Reader) (*metatypes.Metadata, error)\r\n\r\n    Read(key []byte) (data []byte, err error)\r\n    ReadWithMeta(metadata *metatypes.Metadata) (data []byte, err error)\r\n    ReadFile(key []byte, path string, mode FileMode, sync bool) (data []byte, err error)\r\n    ReadFileWithmeta(metadata *metatypes.Metadata, path string, mode FileMode, sync bool) (data []byte, err error)\r\n    ReadStream(key []byte, chunkSize int64, w io.Writer) error\r\n    ReadStreamWithMeta(metadata *metatypes.Metadata, chunkSize int64, w io.Writer) error\r\n\r\n    Delete(key []byte) error\r\n    DeleteWithMeta(metadata *metatypes.Metadata) error\r\n\r\n    Check(key []byte, fast bool) (CheckStatus, error)\r\n    CheckWithMeta(metadata *metatypes.Metadata, fast bool) (CheckStatus, error)\r\n\r\n    Repair(key []byte) (*metatypes.Metadata, error)\r\n}\r\n\r\ntype FileMode uint8\r\n\r\nconst (\r\n    FileModeTruncate FileMode = iota\r\n    FileModeAppend\r\n    FileModeExclusive\r\n)\r\n\r\ntype CheckStatus uint8\r\n\r\nconst (\r\n    CheckStatusInvalid CheckStatus = iota\r\n    CheckStatusValid\r\n    CheckStatusOptimal\r\n)\r\n```\r\n\r\nThis defines the master client, and for many use cases this might be enough.\r\n\r\nIf however you also wish to use IYO, and on top of that manage IYO namespaces and their permissions, the following client is also required:\r\n\r\n```golang\r\ntype NamespaceClient interface {\r\n    CreateNamespace(namespace string) error\r\n    DeleteNamespace(namespace string) error\r\n\r\n    SetPermission(namespace, userID string, permission Permission) error\r\n    GetPermission(namespace, userID string) (*Permission, error)\r\n}\r\n\r\ntype Permission struct {\r\n    Read bool\r\n    Write bool\r\n    Delete bool\r\n    Admin bool\r\n}\r\n```\r\n\r\nIf you wish to set/get/delete metadata directly yourself, you can do so using the following client:\r\n\r\n```golang\r\ntype MetastorClient interface {\r\n    SetMetadata(metadata *metatypes.Metadata) error\r\n    GetMetadata(key []byte) (metadata *metatypes.Metadata, error)\r\n    DeleteMetadata(key []byte) error\r\n}\r\n```\r\n\r\nAnd finally if you wish to store/manage data directly (including pipeline support), you can use the following client:\r\n\r\n```golang\r\ntype DatastorClient interface {\r\n    Write(data []byte) ([]metatypes.Chunk, error)\r\n    WriteFile(filePath string) ([]metatypes.Chunk, error)\r\n    WriteStream(r io.Reader) ([]metatypes.Chunk, error)\r\n\r\n    Read([]metatypes.Chunk) (data []byte, error)\r\n    ReadFile([]metatypes.Chunk, filePath string, mode FileMode, sync bool) error\r\n    ReadStream([]metatypes.Chunk, chunkSize int64, w io.Writer) error\r\n\r\n    Delete([]metatypes.Chunk) error\r\n\r\n    Check([]metatypes.Chunk, fast bool) (CheckStatus, error)\r\n    Repair([]metatypes.Chunk) ([]metatypes.Chunk, error)\r\n}\r\n```\r\n\r\nAll 4 clients can be (and probably should be) implemented separately, and do not (and shouldn't) rely on one another. All clients would be implemented using the generated GRPC code in https://github.com/zero-os/0-stor/blob/master/daemon/api/grpc/schema/daemon.pb.go.\r\n\r\nThe implementation of these clients is fairly straight-forward, but just to make sure, here are some extra pointers to help you out:\r\n\r\n+ Ensure that you never send nil-pointers to the GRPC API, as those will result in a panic from the GRPC Marshal code on your (client) side (this just means that you need to ensure to validate the input you receive from your user in your client methods, prior to turning them into valid proto messages):\r\n+ The daemon server returns the errors as defined in https://github.com/zero-os/0-stor/blob/8b008f089491e1c9ae408aec86756f058ffe8776/daemon/api/grpc/rpctypes/error.go#L26-L41, you can turn them into client-side errors using https://github.com/zero-os/0-stor/blob/8b008f089491e1c9ae408aec86756f058ffe8776/daemon/api/grpc/rpctypes/error.go#L102, this should be done, so users of the client can check for specific errors if required;\r\n\r\nAnd that's about it.\r\n\r\nIn the end you're just wrapping around the generated GRPC client, in order to provide a nice Golang and User friendly client. Should it be the first time you implement such a GRPC-based client, you can get some inspiration in how to use that generated code in the `*_client_test.go` files found in https://github.com/zero-os/0-stor/blob/8b008f089491e1c9ae408aec86756f058ffe8776/daemon/api/grpc.\r\n\r\nGolang Daemon Clients implemented:\r\n\r\n+ [ ] Master Client (using FileService);\r\n+ [ ] Namespace Client (using NamespaceService);\r\n+ [ ] Metastor Client (using MetadataService);\r\n+ [ ] Datastor Client (using DataService);"},"comment":{"url":"https://api.github.com/repos/threefoldtech/0-stor/issues/comments/409581336","html_url":"https://github.com/threefoldtech/0-stor/issues/9#issuecomment-409581336","issue_url":"https://api.github.com/repos/threefoldtech/0-stor/issues/9","id":409581336,"node_id":"MDEyOklzc3VlQ29tbWVudDQwOTU4MTMzNg==","user":{"login":"rkhamis","id":8425762,"node_id":"MDQ6VXNlcjg0MjU3NjI=","avatar_url":"https://avatars1.githubusercontent.com/u/8425762?v=4","gravatar_id":"","url":"https://api.github.com/users/rkhamis","html_url":"https://github.com/rkhamis","followers_url":"https://api.github.com/users/rkhamis/followers","following_url":"https://api.github.com/users/rkhamis/following{/other_user}","gists_url":"https://api.github.com/users/rkhamis/gists{/gist_id}","starred_url":"https://api.github.com/users/rkhamis/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rkhamis/subscriptions","organizations_url":"https://api.github.com/users/rkhamis/orgs","repos_url":"https://api.github.com/users/rkhamis/repos","events_url":"https://api.github.com/users/rkhamis/events{/privacy}","received_events_url":"https://api.github.com/users/rkhamis/received_events","type":"User","site_admin":false},"created_at":"2018-08-01T13:50:18Z","updated_at":"2018-08-01T13:50:18Z","author_association":"NONE","body":"*commented by @GlenDC\nShould you require this Golang client, but only for one specific client (e.g. the master client, which uses the FileService) than it's OK to just implement that one. Certainly do not feel obliged to implement all clients, if all you need is one or two.*"}}
{"actor":{"display_login":"rkhamis"}}