feat: create working client

This commit is contained in:
2026-08-05 13:06:36 +02:00
parent 67916c5d1c
commit aa9d403d09
11 changed files with 3406 additions and 1 deletions

17
buf.gen.yaml Normal file
View File

@@ -0,0 +1,17 @@
version: v2
clean: true
plugins:
- remote: buf.build/protocolbuffers/go:v1.36.11
revision: 1
out: gen
opt:
- module=git.pablu.de/pablu/zw-go/gen
- remote: buf.build/grpc/go:v1.6.2
revision: 1
out: gen
opt:
- module=git.pablu.de/pablu/zw-go/gen
inputs:
- directory: ../zw

293
client.go Normal file
View File

@@ -0,0 +1,293 @@
package zw
import (
"context"
"errors"
"fmt"
"io"
"net/url"
zwdaemonv1 "git.pablu.de/pablu/zw-go/gen/zwdaemon/v1"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
)
const supportedAPIMajor uint32 = 1
func optionalString(value string) *string {
if value == "" {
return nil
}
return &value
}
type Client struct {
conn *grpc.ClientConn
rpc zwdaemonv1.ZwDaemonServiceClient
}
func Connect(ctx context.Context, socketPath string) (*Client, error) {
target := (&url.URL{
Scheme: "unix",
Path: socketPath,
}).String()
conn, err := grpc.NewClient(
target,
grpc.WithTransportCredentials(insecure.NewCredentials()),
)
if err != nil {
return nil, fmt.Errorf("create daemon client: %w", err)
}
client := &Client{
conn: conn,
rpc: zwdaemonv1.NewZwDaemonServiceClient(conn),
}
info, err := client.ServerInfo(ctx)
if err != nil {
_ = conn.Close()
return nil, err
}
if info.APIMajor != supportedAPIMajor {
_ = conn.Close()
return nil, &IncompatibleAPIVersionError{
ServerMajor: info.APIMajor,
ServerMinor: info.APIMinor,
SupportedMajor: supportedAPIMajor,
}
}
return client, nil
}
func (c *Client) Close() error {
return c.conn.Close()
}
func (c *Client) ServerInfo(ctx context.Context) (ServerInfo, error) {
response, err := c.rpc.GetServerInfo(ctx, &zwdaemonv1.GetServerInfoRequest{})
if err != nil {
return ServerInfo{}, convertRPCError(err)
}
return ServerInfo{
APIMajor: response.ApiMajor,
APIMinor: response.ApiMinor,
DaemonVersion: response.DaemonVersion,
}, nil
}
func (c *Client) Create(ctx context.Context, vaultPath string, password string) error {
_, err := c.rpc.Create(ctx, &zwdaemonv1.CreateRequest{
VaultPath: vaultPath,
Password: password,
})
if err != nil {
return convertRPCError(err)
}
return nil
}
func (c *Client) Unseal(ctx context.Context, vaultPath string, password string) error {
_, err := c.rpc.Unseal(ctx, &zwdaemonv1.UnsealRequest{
VaultPath: vaultPath,
Password: password,
})
if err != nil {
return convertRPCError(err)
}
return nil
}
func (c *Client) Seal(ctx context.Context) error {
_, err := c.rpc.Seal(ctx, &zwdaemonv1.SealRequest{})
if err != nil {
return convertRPCError(err)
}
return nil
}
func (c *Client) ListFiles(ctx context.Context, filter ListFilter) ([]ListedFile, error) {
response, err := c.rpc.ListFiles(ctx, &zwdaemonv1.ListFilesRequest{
Prefix: optionalString(filter.Prefix),
Contains: optionalString(filter.Contains),
})
if err != nil {
return nil, convertRPCError(err)
}
files := make([]ListedFile, len(response.GetFiles()))
for index, file := range response.GetFiles() {
files[index] = ListedFile{
LogicalPath: file.GetLogicalPath(),
Size: file.GetSize(),
}
}
return files, nil
}
func (c *Client) ListPaths(ctx context.Context) ([]string, error) {
files, err := c.ListFiles(ctx, ListFilter{})
if err != nil {
return nil, err
}
paths := make([]string, len(files))
for index, file := range files {
paths[index] = file.LogicalPath
}
return paths, nil
}
func (c *Client) DeleteFile(ctx context.Context, logicalPath string) error {
_, err := c.rpc.DeleteFile(ctx, &zwdaemonv1.DeleteFileRequest{
LogicalPath: logicalPath,
})
if err != nil {
return convertRPCError(err)
}
return nil
}
func (c *Client) Compact(ctx context.Context) error {
_, err := c.rpc.Compact(ctx, &zwdaemonv1.CompactRequest{})
if err != nil {
return convertRPCError(err)
}
return nil
}
func (c *Client) GetFile(
ctx context.Context,
logicalPath string,
) (io.ReadCloser, error) {
streamCtx, cancel := context.WithCancel(ctx)
stream, err := c.rpc.GetFile(streamCtx, &zwdaemonv1.GetFileRequest{
LogicalPath: logicalPath,
})
if err != nil {
cancel()
return nil, convertRPCError(err)
}
return &downloadReader{
cancel: cancel,
recv: func() ([]byte, error) {
response, err := stream.Recv()
if err != nil {
return nil, err
}
return response.GetData(), nil
},
}, nil
}
func (c *Client) GetFileRange(
ctx context.Context,
logicalPath string,
start uint64,
exclusiveEnd uint64,
) (io.ReadCloser, error) {
streamCtx, cancel := context.WithCancel(ctx)
stream, err := c.rpc.GetFileRange(streamCtx, &zwdaemonv1.GetFileRangeRequest{
LogicalPath: logicalPath,
Start: start,
ExclusiveEnd: exclusiveEnd,
})
if err != nil {
cancel()
return nil, convertRPCError(err)
}
return &downloadReader{
cancel: cancel,
recv: func() ([]byte, error) {
response, err := stream.Recv()
if err != nil {
return nil, err
}
return response.GetData(), nil
},
}, nil
}
func (c *Client) AddFile(
ctx context.Context,
logicalPath string,
source io.Reader,
sourceLen uint64,
) error {
uploadCtx, cancel := context.WithCancel(ctx)
defer cancel()
stream, err := c.rpc.AddFile(uploadCtx)
if err != nil {
return convertRPCError(err)
}
send := func(request *zwdaemonv1.AddFileRequest) error {
err := stream.Send(request)
if err == nil {
return nil
}
if errors.Is(err, io.EOF) {
_, receiveErr := stream.CloseAndRecv()
if receiveErr != nil {
return convertRPCError(receiveErr)
}
}
return convertRPCError(err)
}
err = send(&zwdaemonv1.AddFileRequest{
Payload: &zwdaemonv1.AddFileRequest_Header{
Header: &zwdaemonv1.AddFileHeader{
LogicalPath: logicalPath,
SourceLen: sourceLen,
},
},
})
if err != nil {
return err
}
const chunkSize = 512 * 1024
buffer := make([]byte, chunkSize)
for {
n, readErr := source.Read(buffer)
if n > 0 {
err := send(&zwdaemonv1.AddFileRequest{
Payload: &zwdaemonv1.AddFileRequest_Chunk{
Chunk: buffer[:n],
},
})
if err != nil {
return err
}
}
switch {
case readErr == nil:
continue
case errors.Is(readErr, io.EOF):
_, err := stream.CloseAndRecv()
if err != nil {
return convertRPCError(err)
}
return nil
default:
return &UploadReadError{Err: readErr}
}
}
}

1024
client_test.go Normal file

File diff suppressed because it is too large Load Diff

71
download.go Normal file
View File

@@ -0,0 +1,71 @@
package zw
import (
"context"
"io"
"io/fs"
"sync"
"sync/atomic"
)
type downloadReader struct {
recv func() ([]byte, error)
cancel context.CancelFunc
pending []byte
terminal error
cancelOnce sync.Once
closed atomic.Bool
}
func (r *downloadReader) Read(destination []byte) (int, error) {
if len(destination) == 0 {
return 0, nil
}
if r.closed.Load() {
return 0, fs.ErrClosed
}
if len(r.pending) > 0 {
n := copy(destination, r.pending)
r.pending = r.pending[n:]
return n, nil
}
if r.terminal != nil {
return 0, r.terminal
}
for {
chunk, err := r.recv()
if err != nil {
if r.closed.Load() {
return 0, fs.ErrClosed
}
if err == io.EOF {
r.terminal = io.EOF
} else {
r.terminal = convertRPCError(err)
}
r.cancelOnce.Do(r.cancel)
return 0, r.terminal
}
if len(chunk) == 0 {
continue
}
n := copy(destination, chunk)
r.pending = chunk[n:]
return n, nil
}
}
func (r *downloadReader) Close() error {
r.closed.Store(true)
r.cancelOnce.Do(r.cancel)
return nil
}

112
errors.go Normal file
View File

@@ -0,0 +1,112 @@
package zw
import (
"fmt"
zwdaemonv1 "git.pablu.de/pablu/zw-go/gen/zwdaemon/v1"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
const zwErrorDetailTypeURL = "type.googleapis.com/zw.daemon.v1.ZwErrorDetail"
type ErrorCode = zwdaemonv1.ZwErrorCode
const (
ErrorCodeUnspecified = zwdaemonv1.ZwErrorCode_ZW_ERROR_CODE_UNSPECIFIED
ErrorCodeVaultSealed = zwdaemonv1.ZwErrorCode_ZW_ERROR_CODE_VAULT_SEALED
ErrorCodeVaultAlreadyUnsealed = zwdaemonv1.ZwErrorCode_ZW_ERROR_CODE_VAULT_ALREADY_UNSEALED
ErrorCodeEntryNotFound = zwdaemonv1.ZwErrorCode_ZW_ERROR_CODE_ENTRY_NOT_FOUND
ErrorCodeEntryAlreadyExists = zwdaemonv1.ZwErrorCode_ZW_ERROR_CODE_ENTRY_ALREADY_EXISTS
ErrorCodeAuthenticationOrCorruption = zwdaemonv1.ZwErrorCode_ZW_ERROR_CODE_AUTHENTICATION_OR_CORRUPTION
ErrorCodeInvalidVaultFormat = zwdaemonv1.ZwErrorCode_ZW_ERROR_CODE_INVALID_VAULT_FORMAT
ErrorCodeUnsupportedVaultVersion = zwdaemonv1.ZwErrorCode_ZW_ERROR_CODE_UNSUPPORTED_VAULT_VERSION
ErrorCodeUnsupportedProtocolVersion = zwdaemonv1.ZwErrorCode_ZW_ERROR_CODE_UNSUPPORTED_PROTOCOL_VERSION
ErrorCodePermissionDenied = zwdaemonv1.ZwErrorCode_ZW_ERROR_CODE_PERMISSION_DENIED
ErrorCodeStorageFull = zwdaemonv1.ZwErrorCode_ZW_ERROR_CODE_STORAGE_FULL
ErrorCodeCommitFailed = zwdaemonv1.ZwErrorCode_ZW_ERROR_CODE_COMMIT_FAILED
ErrorCodeInvalidRequest = zwdaemonv1.ZwErrorCode_ZW_ERROR_CODE_INVALID_REQUEST
ErrorCodeInternal = zwdaemonv1.ZwErrorCode_ZW_ERROR_CODE_INTERNAL
)
type RPCError struct {
GRPCCode codes.Code
ZwCode *ErrorCode
Message string
Retryable bool
status *status.Status
}
func (e *RPCError) Error() string {
return e.Message
}
func (e *RPCError) GRPCStatus() *status.Status {
if e.status != nil {
return e.status
}
return status.New(e.GRPCCode, e.Message)
}
type IncompatibleAPIVersionError struct {
ServerMajor uint32
ServerMinor uint32
SupportedMajor uint32
}
func (e *IncompatibleAPIVersionError) Error() string {
return fmt.Sprintf(
"daemon API version %d.%d is incompatible; this client supports major version %d",
e.ServerMajor,
e.ServerMinor,
e.SupportedMajor,
)
}
type UploadReadError struct {
Err error
}
func (e *UploadReadError) Error() string {
return "read upload source: " + e.Err.Error()
}
func (e *UploadReadError) Unwrap() error {
return e.Err
}
func convertRPCError(err error) error {
if err == nil {
return nil
}
grpcStatus, ok := status.FromError(err)
if !ok {
return err
}
rpcErr := &RPCError{
GRPCCode: grpcStatus.Code(),
Message: grpcStatus.Message(),
status: grpcStatus,
}
for _, detail := range grpcStatus.Proto().GetDetails() {
if detail.GetTypeUrl() != zwErrorDetailTypeURL {
continue
}
var zwDetail zwdaemonv1.ZwErrorDetail
if err := detail.UnmarshalTo(&zwDetail); err != nil {
continue
}
code := zwDetail.GetCode()
rpcErr.ZwCode = &code
rpcErr.Retryable = zwDetail.GetRetryable()
break
}
return rpcErr
}

1352
gen/zwdaemon/v1/daemon.pb.go Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,463 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.6.2
// - protoc (unknown)
// source: zw/daemon/v1/daemon.proto
package zwdaemonv1
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.64.0 or later.
const _ = grpc.SupportPackageIsVersion9
const (
ZwDaemonService_GetServerInfo_FullMethodName = "/zw.daemon.v1.ZwDaemonService/GetServerInfo"
ZwDaemonService_Create_FullMethodName = "/zw.daemon.v1.ZwDaemonService/Create"
ZwDaemonService_Unseal_FullMethodName = "/zw.daemon.v1.ZwDaemonService/Unseal"
ZwDaemonService_Seal_FullMethodName = "/zw.daemon.v1.ZwDaemonService/Seal"
ZwDaemonService_ListFiles_FullMethodName = "/zw.daemon.v1.ZwDaemonService/ListFiles"
ZwDaemonService_GetFile_FullMethodName = "/zw.daemon.v1.ZwDaemonService/GetFile"
ZwDaemonService_GetFileRange_FullMethodName = "/zw.daemon.v1.ZwDaemonService/GetFileRange"
ZwDaemonService_AddFile_FullMethodName = "/zw.daemon.v1.ZwDaemonService/AddFile"
ZwDaemonService_DeleteFile_FullMethodName = "/zw.daemon.v1.ZwDaemonService/DeleteFile"
ZwDaemonService_Compact_FullMethodName = "/zw.daemon.v1.ZwDaemonService/Compact"
)
// ZwDaemonServiceClient is the client API for ZwDaemonService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type ZwDaemonServiceClient interface {
GetServerInfo(ctx context.Context, in *GetServerInfoRequest, opts ...grpc.CallOption) (*GetServerInfoResponse, error)
Create(ctx context.Context, in *CreateRequest, opts ...grpc.CallOption) (*CreateResponse, error)
Unseal(ctx context.Context, in *UnsealRequest, opts ...grpc.CallOption) (*UnsealResponse, error)
Seal(ctx context.Context, in *SealRequest, opts ...grpc.CallOption) (*SealResponse, error)
ListFiles(ctx context.Context, in *ListFilesRequest, opts ...grpc.CallOption) (*ListFilesResponse, error)
GetFile(ctx context.Context, in *GetFileRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[GetFileResponse], error)
GetFileRange(ctx context.Context, in *GetFileRangeRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[GetFileRangeResponse], error)
AddFile(ctx context.Context, opts ...grpc.CallOption) (grpc.ClientStreamingClient[AddFileRequest, AddFileResponse], error)
DeleteFile(ctx context.Context, in *DeleteFileRequest, opts ...grpc.CallOption) (*DeleteFileResponse, error)
Compact(ctx context.Context, in *CompactRequest, opts ...grpc.CallOption) (*CompactResponse, error)
}
type zwDaemonServiceClient struct {
cc grpc.ClientConnInterface
}
func NewZwDaemonServiceClient(cc grpc.ClientConnInterface) ZwDaemonServiceClient {
return &zwDaemonServiceClient{cc}
}
func (c *zwDaemonServiceClient) GetServerInfo(ctx context.Context, in *GetServerInfoRequest, opts ...grpc.CallOption) (*GetServerInfoResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(GetServerInfoResponse)
err := c.cc.Invoke(ctx, ZwDaemonService_GetServerInfo_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *zwDaemonServiceClient) Create(ctx context.Context, in *CreateRequest, opts ...grpc.CallOption) (*CreateResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(CreateResponse)
err := c.cc.Invoke(ctx, ZwDaemonService_Create_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *zwDaemonServiceClient) Unseal(ctx context.Context, in *UnsealRequest, opts ...grpc.CallOption) (*UnsealResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(UnsealResponse)
err := c.cc.Invoke(ctx, ZwDaemonService_Unseal_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *zwDaemonServiceClient) Seal(ctx context.Context, in *SealRequest, opts ...grpc.CallOption) (*SealResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(SealResponse)
err := c.cc.Invoke(ctx, ZwDaemonService_Seal_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *zwDaemonServiceClient) ListFiles(ctx context.Context, in *ListFilesRequest, opts ...grpc.CallOption) (*ListFilesResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(ListFilesResponse)
err := c.cc.Invoke(ctx, ZwDaemonService_ListFiles_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *zwDaemonServiceClient) GetFile(ctx context.Context, in *GetFileRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[GetFileResponse], error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
stream, err := c.cc.NewStream(ctx, &ZwDaemonService_ServiceDesc.Streams[0], ZwDaemonService_GetFile_FullMethodName, cOpts...)
if err != nil {
return nil, err
}
x := &grpc.GenericClientStream[GetFileRequest, GetFileResponse]{ClientStream: stream}
if err := x.ClientStream.SendMsg(in); err != nil {
return nil, err
}
if err := x.ClientStream.CloseSend(); err != nil {
return nil, err
}
return x, nil
}
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type ZwDaemonService_GetFileClient = grpc.ServerStreamingClient[GetFileResponse]
func (c *zwDaemonServiceClient) GetFileRange(ctx context.Context, in *GetFileRangeRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[GetFileRangeResponse], error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
stream, err := c.cc.NewStream(ctx, &ZwDaemonService_ServiceDesc.Streams[1], ZwDaemonService_GetFileRange_FullMethodName, cOpts...)
if err != nil {
return nil, err
}
x := &grpc.GenericClientStream[GetFileRangeRequest, GetFileRangeResponse]{ClientStream: stream}
if err := x.ClientStream.SendMsg(in); err != nil {
return nil, err
}
if err := x.ClientStream.CloseSend(); err != nil {
return nil, err
}
return x, nil
}
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type ZwDaemonService_GetFileRangeClient = grpc.ServerStreamingClient[GetFileRangeResponse]
func (c *zwDaemonServiceClient) AddFile(ctx context.Context, opts ...grpc.CallOption) (grpc.ClientStreamingClient[AddFileRequest, AddFileResponse], error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
stream, err := c.cc.NewStream(ctx, &ZwDaemonService_ServiceDesc.Streams[2], ZwDaemonService_AddFile_FullMethodName, cOpts...)
if err != nil {
return nil, err
}
x := &grpc.GenericClientStream[AddFileRequest, AddFileResponse]{ClientStream: stream}
return x, nil
}
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type ZwDaemonService_AddFileClient = grpc.ClientStreamingClient[AddFileRequest, AddFileResponse]
func (c *zwDaemonServiceClient) DeleteFile(ctx context.Context, in *DeleteFileRequest, opts ...grpc.CallOption) (*DeleteFileResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(DeleteFileResponse)
err := c.cc.Invoke(ctx, ZwDaemonService_DeleteFile_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *zwDaemonServiceClient) Compact(ctx context.Context, in *CompactRequest, opts ...grpc.CallOption) (*CompactResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(CompactResponse)
err := c.cc.Invoke(ctx, ZwDaemonService_Compact_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
// ZwDaemonServiceServer is the server API for ZwDaemonService service.
// All implementations must embed UnimplementedZwDaemonServiceServer
// for forward compatibility.
type ZwDaemonServiceServer interface {
GetServerInfo(context.Context, *GetServerInfoRequest) (*GetServerInfoResponse, error)
Create(context.Context, *CreateRequest) (*CreateResponse, error)
Unseal(context.Context, *UnsealRequest) (*UnsealResponse, error)
Seal(context.Context, *SealRequest) (*SealResponse, error)
ListFiles(context.Context, *ListFilesRequest) (*ListFilesResponse, error)
GetFile(*GetFileRequest, grpc.ServerStreamingServer[GetFileResponse]) error
GetFileRange(*GetFileRangeRequest, grpc.ServerStreamingServer[GetFileRangeResponse]) error
AddFile(grpc.ClientStreamingServer[AddFileRequest, AddFileResponse]) error
DeleteFile(context.Context, *DeleteFileRequest) (*DeleteFileResponse, error)
Compact(context.Context, *CompactRequest) (*CompactResponse, error)
mustEmbedUnimplementedZwDaemonServiceServer()
}
// UnimplementedZwDaemonServiceServer must be embedded to have
// forward compatible implementations.
//
// NOTE: this should be embedded by value instead of pointer to avoid a nil
// pointer dereference when methods are called.
type UnimplementedZwDaemonServiceServer struct{}
func (UnimplementedZwDaemonServiceServer) GetServerInfo(context.Context, *GetServerInfoRequest) (*GetServerInfoResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetServerInfo not implemented")
}
func (UnimplementedZwDaemonServiceServer) Create(context.Context, *CreateRequest) (*CreateResponse, error) {
return nil, status.Error(codes.Unimplemented, "method Create not implemented")
}
func (UnimplementedZwDaemonServiceServer) Unseal(context.Context, *UnsealRequest) (*UnsealResponse, error) {
return nil, status.Error(codes.Unimplemented, "method Unseal not implemented")
}
func (UnimplementedZwDaemonServiceServer) Seal(context.Context, *SealRequest) (*SealResponse, error) {
return nil, status.Error(codes.Unimplemented, "method Seal not implemented")
}
func (UnimplementedZwDaemonServiceServer) ListFiles(context.Context, *ListFilesRequest) (*ListFilesResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListFiles not implemented")
}
func (UnimplementedZwDaemonServiceServer) GetFile(*GetFileRequest, grpc.ServerStreamingServer[GetFileResponse]) error {
return status.Error(codes.Unimplemented, "method GetFile not implemented")
}
func (UnimplementedZwDaemonServiceServer) GetFileRange(*GetFileRangeRequest, grpc.ServerStreamingServer[GetFileRangeResponse]) error {
return status.Error(codes.Unimplemented, "method GetFileRange not implemented")
}
func (UnimplementedZwDaemonServiceServer) AddFile(grpc.ClientStreamingServer[AddFileRequest, AddFileResponse]) error {
return status.Error(codes.Unimplemented, "method AddFile not implemented")
}
func (UnimplementedZwDaemonServiceServer) DeleteFile(context.Context, *DeleteFileRequest) (*DeleteFileResponse, error) {
return nil, status.Error(codes.Unimplemented, "method DeleteFile not implemented")
}
func (UnimplementedZwDaemonServiceServer) Compact(context.Context, *CompactRequest) (*CompactResponse, error) {
return nil, status.Error(codes.Unimplemented, "method Compact not implemented")
}
func (UnimplementedZwDaemonServiceServer) mustEmbedUnimplementedZwDaemonServiceServer() {}
func (UnimplementedZwDaemonServiceServer) testEmbeddedByValue() {}
// UnsafeZwDaemonServiceServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to ZwDaemonServiceServer will
// result in compilation errors.
type UnsafeZwDaemonServiceServer interface {
mustEmbedUnimplementedZwDaemonServiceServer()
}
func RegisterZwDaemonServiceServer(s grpc.ServiceRegistrar, srv ZwDaemonServiceServer) {
// If the following call panics, it indicates UnimplementedZwDaemonServiceServer was
// embedded by pointer and is nil. This will cause panics if an
// unimplemented method is ever invoked, so we test this at initialization
// time to prevent it from happening at runtime later due to I/O.
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
t.testEmbeddedByValue()
}
s.RegisterService(&ZwDaemonService_ServiceDesc, srv)
}
func _ZwDaemonService_GetServerInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetServerInfoRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ZwDaemonServiceServer).GetServerInfo(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ZwDaemonService_GetServerInfo_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ZwDaemonServiceServer).GetServerInfo(ctx, req.(*GetServerInfoRequest))
}
return interceptor(ctx, in, info, handler)
}
func _ZwDaemonService_Create_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(CreateRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ZwDaemonServiceServer).Create(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ZwDaemonService_Create_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ZwDaemonServiceServer).Create(ctx, req.(*CreateRequest))
}
return interceptor(ctx, in, info, handler)
}
func _ZwDaemonService_Unseal_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(UnsealRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ZwDaemonServiceServer).Unseal(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ZwDaemonService_Unseal_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ZwDaemonServiceServer).Unseal(ctx, req.(*UnsealRequest))
}
return interceptor(ctx, in, info, handler)
}
func _ZwDaemonService_Seal_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(SealRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ZwDaemonServiceServer).Seal(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ZwDaemonService_Seal_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ZwDaemonServiceServer).Seal(ctx, req.(*SealRequest))
}
return interceptor(ctx, in, info, handler)
}
func _ZwDaemonService_ListFiles_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ListFilesRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ZwDaemonServiceServer).ListFiles(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ZwDaemonService_ListFiles_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ZwDaemonServiceServer).ListFiles(ctx, req.(*ListFilesRequest))
}
return interceptor(ctx, in, info, handler)
}
func _ZwDaemonService_GetFile_Handler(srv interface{}, stream grpc.ServerStream) error {
m := new(GetFileRequest)
if err := stream.RecvMsg(m); err != nil {
return err
}
return srv.(ZwDaemonServiceServer).GetFile(m, &grpc.GenericServerStream[GetFileRequest, GetFileResponse]{ServerStream: stream})
}
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type ZwDaemonService_GetFileServer = grpc.ServerStreamingServer[GetFileResponse]
func _ZwDaemonService_GetFileRange_Handler(srv interface{}, stream grpc.ServerStream) error {
m := new(GetFileRangeRequest)
if err := stream.RecvMsg(m); err != nil {
return err
}
return srv.(ZwDaemonServiceServer).GetFileRange(m, &grpc.GenericServerStream[GetFileRangeRequest, GetFileRangeResponse]{ServerStream: stream})
}
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type ZwDaemonService_GetFileRangeServer = grpc.ServerStreamingServer[GetFileRangeResponse]
func _ZwDaemonService_AddFile_Handler(srv interface{}, stream grpc.ServerStream) error {
return srv.(ZwDaemonServiceServer).AddFile(&grpc.GenericServerStream[AddFileRequest, AddFileResponse]{ServerStream: stream})
}
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type ZwDaemonService_AddFileServer = grpc.ClientStreamingServer[AddFileRequest, AddFileResponse]
func _ZwDaemonService_DeleteFile_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(DeleteFileRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ZwDaemonServiceServer).DeleteFile(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ZwDaemonService_DeleteFile_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ZwDaemonServiceServer).DeleteFile(ctx, req.(*DeleteFileRequest))
}
return interceptor(ctx, in, info, handler)
}
func _ZwDaemonService_Compact_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(CompactRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ZwDaemonServiceServer).Compact(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ZwDaemonService_Compact_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ZwDaemonServiceServer).Compact(ctx, req.(*CompactRequest))
}
return interceptor(ctx, in, info, handler)
}
// ZwDaemonService_ServiceDesc is the grpc.ServiceDesc for ZwDaemonService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var ZwDaemonService_ServiceDesc = grpc.ServiceDesc{
ServiceName: "zw.daemon.v1.ZwDaemonService",
HandlerType: (*ZwDaemonServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "GetServerInfo",
Handler: _ZwDaemonService_GetServerInfo_Handler,
},
{
MethodName: "Create",
Handler: _ZwDaemonService_Create_Handler,
},
{
MethodName: "Unseal",
Handler: _ZwDaemonService_Unseal_Handler,
},
{
MethodName: "Seal",
Handler: _ZwDaemonService_Seal_Handler,
},
{
MethodName: "ListFiles",
Handler: _ZwDaemonService_ListFiles_Handler,
},
{
MethodName: "DeleteFile",
Handler: _ZwDaemonService_DeleteFile_Handler,
},
{
MethodName: "Compact",
Handler: _ZwDaemonService_Compact_Handler,
},
},
Streams: []grpc.StreamDesc{
{
StreamName: "GetFile",
Handler: _ZwDaemonService_GetFile_Handler,
ServerStreams: true,
},
{
StreamName: "GetFileRange",
Handler: _ZwDaemonService_GetFileRange_Handler,
ServerStreams: true,
},
{
StreamName: "AddFile",
Handler: _ZwDaemonService_AddFile_Handler,
ClientStreams: true,
},
},
Metadata: "zw/daemon/v1/daemon.proto",
}

14
go.mod
View File

@@ -1,3 +1,15 @@
module git.pablu.de/pablu/zw-go module git.pablu.de/pablu/zw-go
go 1.25.0 go 1.26.0
require (
google.golang.org/grpc v1.83.0
google.golang.org/protobuf v1.36.11
)
require (
golang.org/x/net v0.55.0 // indirect
golang.org/x/sys v0.45.0 // indirect
golang.org/x/text v0.37.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa // indirect
)

38
go.sum Normal file
View File

@@ -0,0 +1,38 @@
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
go.opentelemetry.io/otel v1.44.0 h1:JjwHmHpA4iZ3wBxluu2fbbE7j4kqlE8jXyAyPXH7HqU=
go.opentelemetry.io/otel v1.44.0/go.mod h1:BMgjTHL9WPRlRjL2oZCBTL4whCGtXch2H4BhOPIAyYc=
go.opentelemetry.io/otel/metric v1.44.0 h1:1w0gILTcHdr3YI+ixLyjemwrVnsMURbTZFrSYCdDdmc=
go.opentelemetry.io/otel/metric v1.44.0/go.mod h1:8O7hanEPBNgEMmybD3s2VBKcgWOCsA6tzHBPODAiquo=
go.opentelemetry.io/otel/sdk v1.44.0 h1:nHYwb9lK+fJPU/dnT6s7W7Z8itMWyqrnVfbheVYrZ58=
go.opentelemetry.io/otel/sdk v1.44.0/go.mod h1:Osuydd3Se74nqjAKxid74N5eC+jfEqfTegHRnq58oK0=
go.opentelemetry.io/otel/sdk/metric v1.44.0 h1:3LlKgI+VjbVsjNRFZJZAJ30WjXC5VkNRks6si09iEfI=
go.opentelemetry.io/otel/sdk/metric v1.44.0/go.mod h1:5B5pMARnXxKhltooO4xUuCBorl65a4EpnTalObqOigA=
go.opentelemetry.io/otel/trace v1.44.0 h1:jxF5CsGYCe74MCRx2X4g7WsY/VBKRqqpNvXlX/6gtIk=
go.opentelemetry.io/otel/trace v1.44.0/go.mod h1:oLl1jrMQAVo6v3GAggN+1VH9VIz9iUSvW53sW1Q8PIE=
golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8=
golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww=
golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY=
golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc=
golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38=
gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=
gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa h1:mZHHdPZl0dbGHCflZgAq/Q468DWVFcU2whhB2KAo8fk=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
google.golang.org/grpc v1.83.0 h1:JeNZEKJFbQxArAMl+hiytHauacDNqJUllNfmIMmpqnQ=
google.golang.org/grpc v1.83.0/go.mod h1:kDyl6SKsiHKt0uylY5gtn5cEjkrIOhQOGDgIc4JGwzQ=
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=

View File

@@ -1,2 +1,8 @@
[tools] [tools]
go = "1.26.0" go = "1.26.0"
"go:golang.org/x/tools/gopls" = "latest"
buf = "1.72.0"
[tasks.generate]
description = "Generate Go protobuf and gRPC bindings"
run = "buf generate"

17
types.go Normal file
View File

@@ -0,0 +1,17 @@
package zw
type ServerInfo struct {
APIMajor uint32
APIMinor uint32
DaemonVersion string
}
type ListFilter struct {
Prefix string
Contains string
}
type ListedFile struct {
LogicalPath string
Size uint64
}