Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Golang swig bindings #2653

Draft
wants to merge 20 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ if BUILD_PYTHON
include bindings/python/include.am
endif

if BUILD_GO
include bindings/go/include.am
endif

if BUILD_PHP
include bindings/php/include.am
endif
Expand Down
4 changes: 4 additions & 0 deletions bindings/go/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# binding Python: only SWIG auto-generated files
mega.go
megaapi_wrap.cpp
megaapi_wrap.h
3 changes: 3 additions & 0 deletions bindings/go/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module mega

go 1.17
35 changes: 35 additions & 0 deletions bindings/go/include.am
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Output directory for Go bindings
GOBINDIR = bindings/go

# SWIG command for generating Go bindings
SWIG_GO = swig

# Go package name
GOPACKAGE = mega

# SWIG flags for Go bindings
SWIG_GO_FLAGS = -go -cgo -intgosize 64 -c++

# SWIG generated Go source file
GO_SOURCE = $(GOBINDIR)/megaapi_wrap.cpp

# Clean Go bindings files
CLEANFILES += $(GO_SOURCE)
CLEANFILES += $(GOBINDIR)/megaapi_wrap.h
CLEANFILES += $(GOBINDIR)/mega.go
CLEANFILES += $(LIBRARY_PATH)

# Sources for SWIG Go wrapper
nodist_bindings_go_lib_mega_la_SOURCES = $(GO_SOURCE)
bindings_go_lib_mega_la_SOURCES = $(top_srcdir)/bindings/megaapi.i
bindings_go_lib_mega_la_CPPFLAGS = -I$(top_srcdir)/include

$(GO_SOURCE): $(top_srcdir)/bindings/megaapi.i
$(SWIG_GO) $(SWIG_GO_FLAGS) -o $@ -outdir $(GOBINDIR) -package $(GOPACKAGE) -I$(top_srcdir)/include $<
@sed -i 's,#include "megaapi.h",#include "include/megaapi.h",' $(top_srcdir)/$(GOBINDIR)/megaapi_wrap.cpp

.PHONY: go-bindings
go-bindings: $(GO_SOURCE) $(LIBRARY_PATH)

# Ensure that the Go bindings and the shared library are built when requested
all-local: go-bindings
4 changes: 4 additions & 0 deletions bindings/go/package.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package mega

// #cgo LDFLAGS: -L. -L../ -L./libs/ -L../libs/ -lmega
import "C"
6 changes: 6 additions & 0 deletions bindings/megaapi.i
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,12 @@ extern "C" jint JNIEXPORT JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved)

#endif

#ifdef SWIGGO
%include <typemaps.i>
%apply (char *STRING, size_t LENGTH) {(char *buffer, size_t size)};
%apply (char *STRING, size_t LENGTH) {(char *bitmapData, size_t size)};
#endif

%ignore mega::MegaApi::MEGA_DEBRIS_FOLDER;
%ignore mega::MegaNode::getNodeKey;
%ignore mega::MegaNode::getAttrString;
Expand Down
31 changes: 28 additions & 3 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -293,13 +293,13 @@ fi
AC_ARG_ENABLE(sync,
AS_HELP_STRING([--enable-sync], [include sync subsystem [default=yes]]),
[enable_sync=$enableval
if test "x$enable_sync" = "xyes" && (test "x$enable_java" = "xyes" || test "x$enable_python" = "xyes" || test "x$enable_php" = "xyes"); then
if test "x$enable_sync" = "xyes" && (test "x$enable_java" = "xyes" || test "x$enable_python" = "xyes" || test "x$enable_go" = "xyes" || test "x$enable_php" = "xyes"); then
AC_MSG_ERROR([--enable-sync not allowed when building bindings (php/python/java)!])
fi
],
[enable_sync=yes])

if test "x$enable_java" = "xyes" || test "x$enable_python" = "xyes" || test "x$enable_php" = "xyes" ; then
if test "x$enable_java" = "xyes" || test "x$enable_python" = "xyes" || test "x$enable_go" = "xyes" || test "x$enable_php" = "xyes" ; then
enable_sync=no
fi

Expand Down Expand Up @@ -433,7 +433,7 @@ AM_CONDITIONAL([BUILD_JAVA], [test "$enable_java" = "yes"])
AC_ARG_ENABLE(chat,
AS_HELP_STRING([--enable-chat], [enable chat support]),
[], [enable_chat=no])
if test "x$enable_chat" = "xyes" || test "x$enable_java" = "xyes" || test "x$enable_python" = "xyes" || test "x$enable_php" = "xyes" ; then
if test "x$enable_chat" = "xyes" || test "x$enable_java" = "xyes" || test "x$enable_python" = "xyes" || test "x$enable_go" = "xyes" || test "x$enable_php" = "xyes" ; then
enable_chat=yes
AC_DEFINE(ENABLE_CHAT, 1, [Define to enable chat])
fi
Expand Down Expand Up @@ -2172,6 +2172,30 @@ if test "x$enable_python" = "xyes" ; then
fi
AM_CONDITIONAL([BUILD_PYTHON], [test "$enable_python" = "yes"])

# GO Lang
AC_MSG_CHECKING([if building Go bindings])
AC_ARG_ENABLE(go,
AS_HELP_STRING([--enable-go], [build Go language bindings]),
[AC_MSG_RESULT([$enableval])],
[
AC_MSG_RESULT([$enableval])
enable_go=no]
)

if test "x$enable_go" = "xyes" ; then
AX_PKG_SWIG(2.0.0, [], [
AC_MSG_ERROR([SWIG executable not found!])
])
AX_SWIG_ENABLE_CXX
AX_SWIG_MULTI_MODULE_SUPPORT

if test -z "$SWIG"; then
AC_MSG_ERROR([SWIG executable not found!])
fi

fi
AM_CONDITIONAL([BUILD_GO], [test "$enable_go" = "yes"])

# PHP
AC_MSG_CHECKING([if building PHP bindings])
AC_ARG_ENABLE(php,
Expand Down Expand Up @@ -2288,6 +2312,7 @@ AC_MSG_NOTICE([Configured to build Mega SDK:
Python bindings: $enable_python
Python3 bindings: $USE_PYTHON3
Go bindings:: $enable_go
PHP bindings: $enable_php
SWIG_FLAGS_PHP: $SWIG_FLAGS_PHP
Expand Down
143 changes: 143 additions & 0 deletions examples/go/fs-test/browse.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
package main

// To build:
// ./autogen.sh && ./configure --disable-silent-rules --enable-go --disable-examples && make -j16
// cd examples/go
// ./prep.sh
// LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./libs go run -x ./main.go

// TODO: ./configure --enable-static results in sqlite3 issues with libmega.a?

import (
"fmt"
"sync"
"time"

mega "example_project/mega"
)

type MyMegaListener struct {
mega.SwigDirector_MegaListener
notified bool
err *mega.MegaError
request *mega.MegaRequest
m sync.Mutex
cv *sync.Cond
cwd *mega.MegaNode
}

func (l *MyMegaListener) OnRequestFinish(api mega.MegaApi, request mega.MegaRequest, e mega.MegaError) {
req := request.Copy()
err := e.Copy()
l.request = &req
l.err = &err

if err.GetErrorCode() != mega.MegaErrorAPI_OK {
fmt.Printf("INFO: Request finished with error\n")
return
}

l.m.Lock()
defer l.m.Unlock()

switch request.GetType() {
case mega.MegaRequestTYPE_LOGIN:
fmt.Printf("Fetching nodes. Please wait...\n")
api.FetchNodes()
case mega.MegaRequestTYPE_FETCH_NODES:
fmt.Printf("Account correctly loaded\n")
node := api.GetRootNode()
l.cwd = &node
}

l.notified = true
l.cv.Broadcast()
}

func (l *MyMegaListener) OnNodesUpdate(api mega.MegaApi, nodes mega.MegaNodeList) {
if nodes.Swigcptr() == 0 {
node := api.GetRootNode()
l.cwd = &node
} else {
fmt.Printf("INFO: Nodes updated\n")
}
}

func (l *MyMegaListener) GetError() *mega.MegaError {
return l.err
}

func (l *MyMegaListener) GetRequest() *mega.MegaRequest {
return l.request
}

func (l *MyMegaListener) Wait() {
// Wait until notified becomes true
l.m.Lock()
defer l.m.Unlock()

for !l.notified {
l.cv.Wait()
}
}

func (l *MyMegaListener) Reset() {
l.err = nil
l.request = nil
l.notified = false
}

func main() {
myListener := MyMegaListener{}
myListener.cv = sync.NewCond(&myListener.m)
listener := mega.NewDirectorMegaListener(&myListener)

fmt.Println("Hello, World!")
api := mega.NewMegaApi("ht1gUZLZ", "", "MEGA/SDK fs test")
api.AddListener(listener)

user, pass := getAuth()
api.Login(user, pass)
defer api.Logout()
myListener.Wait()

if (*myListener.GetError()).GetErrorCode() != mega.MegaErrorAPI_OK {
fmt.Println("Login error")
return
}
myListener.Reset()

for myListener.cwd == nil {
// Give the terminal a chance to print the stuff it wants
time.Sleep(1 * time.Second)
}

node := api.GetNodeByPath("/")
if node.Swigcptr() == 0 {
fmt.Println("Failed to read node!")
return
}

children := api.GetChildren(node)
if children.Swigcptr() == 0 {
fmt.Println("Failed to list files!")
return
}

fmt.Printf("Number of children: %d\n", children.Size())
for i := 0; i < children.Size(); i++ {
node := children.Get(i)
fmt.Printf("%s -> IsFile: %t\n", node.GetName(), node.IsFile())
}

fmt.Println("Done!")
}

func getAuth() (username string, password string) {
fmt.Print("Enter your username: ")
fmt.Scan(&username)

fmt.Print("Enter your password: ")
fmt.Scan(&password)
return
}
7 changes: 7 additions & 0 deletions examples/go/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module example_project

go 1.18

replace example_project/mega => ./megasdk

require example_project/mega v0.0.0-00010101000000-000000000000
Loading