You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: iocgo.go
    path of file: ./repos/IOC-golang/extension/autowire/rpc/protocol/protocol_impl
    
    the code of the file until where you have to start completion: /*
 * Copyright (c) 2022, Alibaba Group;
 * 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.
 */

package protocol_impl

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"time"

	"github.com/alibaba/ioc-golang/extension/autowire/rpc/proxy"

	"github.com/alibaba/ioc-golang/aop"
	"github.com/alibaba/ioc-golang/autowire"
	"github.com/alibaba/ioc-golang/logger"

	"dubbo.apache.org/dubbo-go/v3/protocol/invocation"
	"github.com/gin-gonic/gin"

	"dubbo.apache.org/dubbo-go/v3/common/constant"
	dubboProtocol "dubbo.apache.org/dubbo-go/v3/protocol"

	"github.com/alibaba/ioc-golang/extension/autowire/rpc/protocol"
)

// +ioc:autowire=true
// +ioc:autowire:type=normal
// +ioc:autowire:paramType=Param
// +ioc:autowire:constructFunc=Init

// IOCProtocol is ioc protocol impl
type IOCProtocol struct {
	address    string
	exportPort string
	
    
func (i *IOCProtocol) Invoke(invocation dubboProtocol.Invocation) dubboProtocol.Result {
	sdID, _ := invocation.GetAttachment("sdid")
	data, _ := json.Marshal(invocation.Arguments())
	invokeURL := DefaultSchema + "://" + i.address + "/" + sdID + "/" + invocation.MethodName()

	timeoutDuration, err := time.ParseDuration(i.timeout)
	if err != nil {
		timeoutDuration = time.Second * 3
	}
	requestCtx, cancel := context.WithTimeout(context.Background(), timeoutDuration)
	defer cancel()
	req, err := http.NewRequestWithContext(requestCtx, http.MethodPost, invokeURL, bytes.NewBuffer(data))
	if err != nil {
		return &dubboProtocol.RPCResult{
			Err: err,
		}
	}

	allRPCInterceptors := aop.GetRPCInterceptors()
	for _, rpcInterceptor := range allRPCInterceptors {
		if err := rpcInterceptor.BeforeClientInvoke(req); err != nil {
			return &dubboProtocol.RPCResult{
				Err: err,
			}
		}
	}

	rsp, err := http.DefaultClient.Do(req)
	if err != nil {
		logger.Red("[IOC Protocol] Invoke %s with error = %s", invokeURL, err)
		return &dubboProtocol.RPCResult{
			Err: err,
		}
	}

	for _, rpcInterceptor := range allRPCInterceptors {
		if err := rpcInterceptor.AfterClientInvoke(rsp); err != nil {
			return &dubboProtocol.RPCResult{
				Err: err,
			}
		}
	}

	rspData, _ := ioutil.ReadAll(rsp.Body)
	replyList := invocation.Reply().(*[]interface{})
	finalIsError := false
	finalErrorNotNil := false
	if length := len(*replyList); length > 0 {
		_, ok := (*replyList)[length-1].(*error)
		if ok {
			finalIsError = true
		}
	}
	err = json.Unmarshal(rspData, replyList)
	if err != nil && finalIsError {
		// error message must be returned
		finalErrorNotNil = true

		// calculate error message detail, try to recover unmarshal failed caused by error not empty, first try to unmarshal to string
		(*replyList)[len(*replyList)-1] = ""
		err = json.Unmarshal(rspData, replyList)
		if err != nil {
			// error is not nil, means previous unmarshal failed because of invalid response, write error message
			err = fmt.Errorf("[IOC Protocol] Unmarshal response from %s with error %s, response data details is %s", invokeURL, err, string(rspData))
			(*replyList)[len(*replyList)-1] = err
		}
		// error is nil means final return value error is returned from server side, and the response is valid
	}
	if err != nil {
		return &dubboProtocol.RPCResult{
			Err: err,
		}
	}
	if finalErrorNotNil {
		realErr := fmt.Errorf((*replyList)[len(*replyList)-1].(string))
		(*replyList)[len(*replyList)-1] = &realErr
	}
	return nil
}