bindings/go/write.go (162 lines of code) (raw):
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package opendal
import (
"context"
"io"
"unsafe"
"github.com/jupiterrider/ffi"
)
// Write writes the given bytes to the specified path.
//
// Write is a wrapper around the C-binding function `opendal_operator_write`. It provides a simplified
// interface for writing data to the storage. Currently, this implementation does not support the
// `Operator::write_with` method from the original Rust library, nor does it support streaming writes
// or multipart uploads.
//
// # Parameters
//
// - path: The destination path where the bytes will be written.
// - data: The byte slice containing the data to be written.
//
// # Returns
//
// - error: An error if the write operation fails, or nil if successful.
//
// # Example
//
// func exampleWrite(op *opendal.Operator) {
// err = op.Write("test", []byte("Hello opendal go binding!"))
// if err != nil {
// log.Fatal(err)
// }
// }
//
// Note: This example assumes proper error handling and import statements.
func (op *Operator) Write(path string, data []byte) error {
write := getFFI[operatorWrite](op.ctx, symOperatorWrite)
return write(op.inner, path, data)
}
// CreateDir creates a directory at the specified path.
//
// CreateDir is a wrapper around the C-binding function `opendal_operator_create_dir`.
// It provides a way to create directories in the storage system.
//
// # Parameters
//
// - path: The path where the directory should be created.
//
// # Returns
//
// - error: An error if the directory creation fails, or nil if successful.
//
// # Notes
//
// It is mandatory to include a trailing slash (/) in the path to indicate
// that it is a directory. Failing to do so may result in a `CodeNotADirectory`
// error being returned by OpenDAL.
//
// # Behavior
//
// - Creating a directory that already exists will succeed without error.
// - Directory creation is always recursive, similar to the `mkdir -p` command.
//
// # Example
//
// func exampleCreateDir(op *opendal.Operator) {
// err = op.CreateDir("test/")
// if err != nil {
// log.Fatal(err)
// }
// }
//
// Note: This example assumes proper error handling and import statements.
// The trailing slash in "test/" is important to indicate it's a directory.
func (op *Operator) CreateDir(path string) error {
createDir := getFFI[operatorCreateDir](op.ctx, symOperatorCreateDir)
return createDir(op.inner, path)
}
// Writer returns a new Writer for the specified path.
//
// Writer is a wrapper around the C-binding function `opendal_operator_writer`.
// It provides a way to obtain a writer for writing data to the storage system.
//
// # Parameters
//
// - path: The destination path where data will be written.
//
// # Returns
//
// - *Writer: A pointer to a Writer instance, or an error if the operation fails.
//
// # Example
//
// func exampleWriter(op *opendal.Operator) {
// writer, err := op.Writer("test/")
// if err != nil {
// log.Fatal(err)
// }
// defer writer.Close()
// _, err = writer.Write([]byte("Hello opendal writer!"))
// if err != nil {
// log.Fatal(err)
// }
// }
//
// Note: This example assumes proper error handling and import statements.
func (op *Operator) Writer(path string) (*Writer, error) {
getWriter := getFFI[operatorWriter](op.ctx,
symOperatorWriter)
inner, err := getWriter(op.inner, path)
if err != nil {
return nil, err
}
writer := &Writer{
inner: inner,
ctx: op.ctx,
}
return writer, nil
}
type Writer struct {
inner *opendalWriter
ctx context.Context
}
// Write writes the given bytes to the specified path.
//
// Write is a wrapper around the C-binding function `opendal_operator_write`. It provides a simplified
// interface for writing data to the storage. Write can be called multiple times to write
// additional data to the same path.
//
// The maximum size of the data that can be written in a single call is 256KB.
//
// # Parameters
//
// - path: The destination path where the bytes will be written.
// - data: The byte slice containing the data to be written.
//
// # Returns
//
// - error: An error if the write operation fails, or nil if successful.
//
// # Example
//
// func exampleWrite(op *opendal.Operator) {
// err = op.Write("test", []byte("Hello opendal go binding!"))
// if err != nil {
// log.Fatal(err)
// }
// }
//
// Note: This example assumes proper error handling and import statements.
func (w *Writer) Write(p []byte) (n int, err error) {
write := getFFI[writerWrite](w.ctx, symWriterWrite)
return write(w.inner, p)
}
// Close finishes the write and releases the resources associated with the Writer.
// It is important to call Close after writing all the data to ensure that the data is
// properly flushed and written to the storage. Otherwise, the data may be lost.
func (w *Writer) Close() error {
free := getFFI[writerFree](w.ctx, symWriterFree)
defer free(w.inner)
close := getFFI[writerClose](w.ctx, symWriterClose)
return close(w.inner)
}
var _ io.WriteCloser = (*Writer)(nil)
const symOperatorWrite = "opendal_operator_write"
type operatorWrite func(op *opendalOperator, path string, data []byte) error
var withOperatorWrite = withFFI(ffiOpts{
sym: symOperatorWrite,
rType: &ffi.TypePointer,
aTypes: []*ffi.Type{&ffi.TypePointer, &ffi.TypePointer, &ffi.TypePointer},
}, func(ctx context.Context, ffiCall func(rValue unsafe.Pointer, aValues ...unsafe.Pointer)) operatorWrite {
return func(op *opendalOperator, path string, data []byte) error {
bytePath, err := BytePtrFromString(path)
if err != nil {
return err
}
bytes := toOpendalBytes(data)
var e *opendalError
ffiCall(
unsafe.Pointer(&e),
unsafe.Pointer(&op),
unsafe.Pointer(&bytePath),
unsafe.Pointer(&bytes),
)
return parseError(ctx, e)
}
})
const symOperatorCreateDir = "opendal_operator_create_dir"
type operatorCreateDir func(op *opendalOperator, path string) error
var withOperatorCreateDir = withFFI(ffiOpts{
sym: symOperatorCreateDir,
rType: &ffi.TypePointer,
aTypes: []*ffi.Type{&ffi.TypePointer, &ffi.TypePointer},
}, func(ctx context.Context, ffiCall func(rValue unsafe.Pointer, aValues ...unsafe.Pointer)) operatorCreateDir {
return func(op *opendalOperator, path string) error {
bytePath, err := BytePtrFromString(path)
if err != nil {
return err
}
var e *opendalError
ffiCall(
unsafe.Pointer(&e),
unsafe.Pointer(&op),
unsafe.Pointer(&bytePath),
)
return parseError(ctx, e)
}
})
const symOperatorWriter = "opendal_operator_writer"
type operatorWriter func(op *opendalOperator, path string) (*opendalWriter, error)
var withOperatorWriter = withFFI(ffiOpts{
sym: symOperatorWriter,
rType: &typeResultOperatorWriter,
aTypes: []*ffi.Type{&ffi.TypePointer, &ffi.TypePointer},
}, func(ctx context.Context, ffiCall func(rValue unsafe.Pointer, aValues ...unsafe.Pointer)) operatorWriter {
return func(op *opendalOperator, path string) (*opendalWriter, error) {
bytePath, err := BytePtrFromString(path)
if err != nil {
return nil, err
}
var result resultOperatorWriter
ffiCall(
unsafe.Pointer(&result),
unsafe.Pointer(&op),
unsafe.Pointer(&bytePath),
)
if result.error != nil {
return nil, parseError(ctx, result.error)
}
return result.writer, nil
}
})
const symWriterFree = "opendal_writer_free"
type writerFree func(w *opendalWriter)
var withWriterFree = withFFI(ffiOpts{
sym: symWriterFree,
rType: &ffi.TypeVoid,
aTypes: []*ffi.Type{&ffi.TypePointer},
}, func(ctx context.Context, ffiCall func(rValue unsafe.Pointer, aValues ...unsafe.Pointer)) writerFree {
return func(r *opendalWriter) {
ffiCall(
nil,
unsafe.Pointer(&r),
)
}
})
const symWriterWrite = "opendal_writer_write"
type writerWrite func(r *opendalWriter, buf []byte) (size int, err error)
var withWriterWrite = withFFI(ffiOpts{
sym: symWriterWrite,
rType: &typeResultWriterWrite,
aTypes: []*ffi.Type{&ffi.TypePointer, &ffi.TypePointer},
}, func(ctx context.Context, ffiCall func(rValue unsafe.Pointer, aValues ...unsafe.Pointer)) writerWrite {
return func(r *opendalWriter, data []byte) (size int, err error) {
bytes := toOpendalBytes(data)
var result resultWriterWrite
ffiCall(
unsafe.Pointer(&result),
unsafe.Pointer(&r),
unsafe.Pointer(&bytes),
)
if result.error != nil {
return 0, parseError(ctx, result.error)
}
return int(result.size), nil
}
})
const symWriterClose = "opendal_writer_close"
type writerClose func(r *opendalWriter) error
var withWriterClose = withFFI(ffiOpts{
sym: symWriterClose,
rType: &ffi.TypePointer,
aTypes: []*ffi.Type{&ffi.TypePointer},
}, func(ctx context.Context, ffiCall func(rValue unsafe.Pointer, aValues ...unsafe.Pointer)) writerClose {
return func(r *opendalWriter) error {
var e *opendalError
ffiCall(
unsafe.Pointer(&e),
unsafe.Pointer(&r),
)
return parseError(ctx, e)
}
})