Skip to content

Commit

Permalink
feat: add wasm multipart upload (#108)
Browse files Browse the repository at this point in the history
* fix: message status change

* fix: page pull change args

* feat: add wasm multipart upload

* feat: add wasm multipart upload
  • Loading branch information
FGadvancer authored Jul 13, 2023
1 parent 8244876 commit 5e7956a
Show file tree
Hide file tree
Showing 24 changed files with 569 additions and 468 deletions.
15 changes: 0 additions & 15 deletions .vscode/launch.json

This file was deleted.

8 changes: 0 additions & 8 deletions .vscode/settings.json

This file was deleted.

68 changes: 68 additions & 0 deletions internal/conversation_msg/file_js.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Copyright © 2023 OpenIM SDK. All rights reserved.
//
// Licensed 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.

//go:build js && wasm
// +build js,wasm

package conversation_msg

import (
"open_im_sdk/wasm/exec"
"syscall/js"
)

type JSFile struct {
}

func NewFile() *JSFile {
return &JSFile{}
}
func (j *JSFile) Open(uuid string) (int64, error) {
return WasmOpen(uuid)
}

func (j *JSFile) Read(uuid string, offset int64, length int64) ([]byte, error) {
return WasmRead(uuid, offset, length)
}

func (j *JSFile) Close(uuid string) error {
return WasmClose(uuid)
}

func WasmOpen(uuid string) (int64, error) {
result, err := exec.Exec(uuid)
if err != nil {
return 0, err
}
if v, ok := result.(float64); ok {
return int64(v), nil
}
return 0, exec.ErrType
}
func WasmRead(uuid string, offset int64, length int64) ([]byte, error) {
result, err := exec.Exec(uuid, offset, length)
if err != nil {
return nil, err
} else {
if v, ok := result.(js.Value); ok {
return exec.ExtractArrayBuffer(v), nil
} else {
return nil, exec.ErrType
}
}
}
func WasmClose(uuid string) error {
_, err := exec.Exec(uuid)
return err
}
12 changes: 2 additions & 10 deletions internal/conversation_msg/sdk.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import (
"open_im_sdk/pkg/db/model_struct"
"open_im_sdk/pkg/sdkerrs"
"path/filepath"
"runtime"
"sort"
"strings"
"sync"
Expand Down Expand Up @@ -395,15 +394,8 @@ func (c *Conversation) SendMessage(ctx context.Context, s *sdk_struct.MsgStruct,
return nil, err
}
} else {
//if oldMessage.Status != constant.MsgStatusSendFailed {
// return nil, sdkerrs.ErrMsgRepeated
//} else {
// s.Status = constant.MsgStatusSending
//}
//opy from v2.3.0,May need to be modified
if oldMessage.Status == constant.MsgStatusSendSuccess {
callback.OnSuccess(utils.StructToJsonString(oldMessage))
runtime.Goexit()
if oldMessage.Status != constant.MsgStatusSendFailed {
return nil, sdkerrs.ErrMsgRepeated
} else {
s.Status = constant.MsgStatusSending
}
Expand Down
4 changes: 2 additions & 2 deletions internal/util/post.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,8 @@ func CallApi[T any](ctx context.Context, api string, req any) (*T, error) {
func GetPageAll[A interface {
GetPagination() *sdkws.RequestPagination
}, B, C any](ctx context.Context, api string, req A, fn func(resp *B) []C) ([]C, error) {
if req.GetPagination().ShowNumber == 0 {
req.GetPagination().ShowNumber = 50 / 10
if req.GetPagination().ShowNumber <= 0 {
req.GetPagination().ShowNumber = 50
}
var res []C
for i := int32(0); ; i++ {
Expand Down
6 changes: 3 additions & 3 deletions pkg/db/db_js.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@

package db

import "context"

import (
"context"
"errors"
"open_im_sdk/wasm/exec"
"open_im_sdk/wasm/indexdb"
)

Expand Down Expand Up @@ -47,7 +47,7 @@ func (i IndexDB) Close(ctx context.Context) error {
}

func (i IndexDB) InitDB(ctx context.Context, userID string, dataDir string) error {
_, err := indexdb.Exec(userID, dataDir)
_, err := exec.Exec(userID, dataDir)
return err
}

Expand Down
10 changes: 2 additions & 8 deletions wasm/event_listener/caller.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"errors"
"open_im_sdk/pkg/log"
"open_im_sdk/pkg/utils"
"open_im_sdk/wasm/exec"
"reflect"
"strconv"
"strings"
Expand All @@ -37,13 +38,6 @@ type Caller interface {
SyncCall() (result []interface{})
}

func extractArrayBuffer(arrayBuffer js.Value) []byte {
uint8Array := js.Global().Get("Uint8Array").New(arrayBuffer)
dst := make([]byte, uint8Array.Length())
js.CopyBytesToGo(dst, uint8Array)
return dst
}

type FuncLogic func()

var ErrNotSetCallback = errors.New("not set callback to call")
Expand Down Expand Up @@ -118,7 +112,7 @@ func (r *ReflectCall) asyncCallWithCallback() {
case reflect.Int64:
values = append(values, reflect.ValueOf(int64(r.arguments[i].Int())))
case reflect.Ptr:
values = append(values, reflect.ValueOf(bytes.NewBuffer(extractArrayBuffer(r.arguments[i]))))
values = append(values, reflect.ValueOf(bytes.NewBuffer(exec.ExtractArrayBuffer(r.arguments[i]))))
default:
log.Error("AsyncCallWithCallback", "input args type not support:", strconv.Itoa(int(typeFuncName.In(temp).Kind())))
panic("input args type not support:" + strconv.Itoa(int(typeFuncName.In(temp).Kind())))
Expand Down
140 changes: 140 additions & 0 deletions wasm/exec/executor.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
// Copyright © 2023 OpenIM SDK. All rights reserved.
//
// Licensed 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.

//go:build js && wasm
// +build js,wasm

package exec

import (
"errors"
"open_im_sdk/pkg/log"
"open_im_sdk/pkg/utils"
"runtime"
"syscall/js"
"time"
)

type CallbackData struct {
ErrCode int32 `json:"errCode"`
ErrMsg string `json:"errMsg"`
Data interface{} `json:"data"`
}

const TIMEOUT = 5

var ErrType = errors.New("from javascript data type err")
var PrimaryKeyNull = errors.New("primary key is null err")

var ErrTimoutFromJavaScript = errors.New("invoke javascript timeout,maybe should check function from javascript")
var jsErr = js.Global().Get("Error")

func Exec(args ...interface{}) (output interface{}, err error) {
defer func() {
if r := recover(); r != nil {
switch x := r.(type) {
case string:
err = utils.Wrap(errors.New(x), "")
case error:
err = x
default:
err = utils.Wrap(errors.New("unknown panic"), "")
}
}
}()
thenChannel := make(chan []js.Value)
defer close(thenChannel)
catchChannel := make(chan []js.Value)
defer close(catchChannel)
pc, _, _, _ := runtime.Caller(1)
funcName := utils.CleanUpfuncName(runtime.FuncForPC(pc).Name())
data := CallbackData{}
thenFunc := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
defer func() {
if r := recover(); r != nil {
switch x := r.(type) {
case string:
err = utils.Wrap(errors.New(x), "")
case error:
err = x
default:
err = utils.Wrap(errors.New("unknown panic"), "")
}
}
}()
log.Debug("js then funcation", "=> (main go context) "+funcName+" with respone ", args[0].String())
thenChannel <- args
return nil
})
defer thenFunc.Release()
catchFunc := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
defer func() {
if r := recover(); r != nil {
switch x := r.(type) {
case string:
err = utils.Wrap(errors.New(x), "")
case error:
err = x
default:
err = utils.Wrap(errors.New("unknown panic"), "")
}
}
}()
log.Debug("js catch funcation", "=> (main go context) "+funcName+" with respone ", args[0].String())
catchChannel <- args
return nil
})
defer catchFunc.Release()
js.Global().Call(utils.FirstLower(funcName), args...).Call("then", thenFunc).Call("catch", catchFunc)
select {
case result := <-thenChannel:
if len(result) > 0 {
switch result[0].Type() {
case js.TypeString:
interErr := utils.JsonStringToStruct(result[0].String(), &data)
if interErr != nil {
err = utils.Wrap(err, "return json unmarshal err from javascript")
}
case js.TypeObject:
return result[0], nil

default:
err = errors.New("unkown return type from javascript")
}

} else {
err = errors.New("args err,length is 0")
}

case catch := <-catchChannel:
if catch[0].InstanceOf(jsErr) {
return nil, js.Error{Value: catch[0]}
} else {
panic("unknown javascript exception")
}
case <-time.After(TIMEOUT * time.Second):
panic(ErrTimoutFromJavaScript)
}
if data.ErrCode != 0 {
return "", errors.New(data.ErrMsg)
}
return data.Data, err
}

func ExtractArrayBuffer(arrayBuffer js.Value) []byte {
uint8Array := js.Global().Get("Uint8Array").New(arrayBuffer)
dst := make([]byte, uint8Array.Length())
js.CopyBytesToGo(dst, uint8Array)
return dst
}
Loading

0 comments on commit 5e7956a

Please sign in to comment.