Skip to content
Snippets Groups Projects
rest_protocol.go 5.13 KiB
Newer Older
Patrick's avatar
Patrick committed
/*
 * 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.
 */

Patrick's avatar
Patrick committed
package rest

Patrick's avatar
Patrick committed
import (
	"sync"
	"time"
)

Patrick's avatar
Patrick committed
import (
	"github.com/apache/dubbo-go/common"
Patrick's avatar
Patrick committed
	"github.com/apache/dubbo-go/common/constant"
	"github.com/apache/dubbo-go/common/extension"
Patrick's avatar
Patrick committed
	"github.com/apache/dubbo-go/common/logger"
Patrick's avatar
Patrick committed
	"github.com/apache/dubbo-go/config"
Patrick's avatar
Patrick committed
	"github.com/apache/dubbo-go/protocol"
Patrick's avatar
Patrick committed
	"github.com/apache/dubbo-go/protocol/rest/client"
	_ "github.com/apache/dubbo-go/protocol/rest/client/client_impl"
fangyincheng's avatar
fangyincheng committed
	rest_config "github.com/apache/dubbo-go/protocol/rest/config"
	_ "github.com/apache/dubbo-go/protocol/rest/config/reader"
Patrick's avatar
Patrick committed
	"github.com/apache/dubbo-go/protocol/rest/server"
	_ "github.com/apache/dubbo-go/protocol/rest/server/server_impl"
Patrick's avatar
Patrick committed
)

var (
	restProtocol *RestProtocol
)

Patrick's avatar
Patrick committed
const REST = "rest"

lihaowei's avatar
lihaowei committed
// nolint
Patrick's avatar
Patrick committed
func init() {
	extension.SetProtocol(REST, GetRestProtocol)
}

lihaowei's avatar
lihaowei committed
// nolint
Patrick's avatar
Patrick committed
type RestProtocol struct {
	protocol.BaseProtocol
	serverLock sync.Mutex
Patrick's avatar
Patrick committed
	serverMap  map[string]server.RestServer
	clientLock sync.Mutex
Patrick's avatar
Patrick committed
	clientMap  map[client.RestOptions]client.RestClient
Patrick's avatar
Patrick committed
}

lihaowei's avatar
lihaowei committed
// NewRestProtocol returns a RestProtocol
Patrick's avatar
Patrick committed
func NewRestProtocol() *RestProtocol {
Patrick's avatar
Patrick committed
	return &RestProtocol{
		BaseProtocol: protocol.NewBaseProtocol(),
Patrick's avatar
Patrick committed
		serverMap:    make(map[string]server.RestServer, 8),
		clientMap:    make(map[client.RestOptions]client.RestClient, 8),
Patrick's avatar
Patrick committed
	}
Patrick's avatar
Patrick committed
}

lihaowei's avatar
lihaowei committed
// Export export rest service
Patrick's avatar
Patrick committed
func (rp *RestProtocol) Export(invoker protocol.Invoker) protocol.Exporter {
	url := invoker.GetUrl()
Patrick's avatar
Patrick committed
	serviceKey := url.ServiceKey()
	exporter := NewRestExporter(serviceKey, invoker, rp.ExporterMap())
Patrick's avatar
Patrick committed
	id := url.GetParam(constant.BEAN_NAME_KEY, "")
	restServiceConfig := rest_config.GetRestProviderServiceConfig(id)
Patrick's avatar
Patrick committed
	if restServiceConfig == nil {
		logger.Errorf("%s service doesn't has provider config", url.Path)
		return nil
	}
	rp.SetExporterMap(serviceKey, exporter)
Patrick's avatar
Patrick committed
	restServer := rp.getServer(url, restServiceConfig.Server)
	for _, methodConfig := range restServiceConfig.RestMethodConfigsMap {
		restServer.Deploy(methodConfig, server.GetRouteFunc(invoker, methodConfig))
	}
	return exporter
Patrick's avatar
Patrick committed
}

lihaowei's avatar
lihaowei committed
// Refer create rest service reference
haohongfan's avatar
haohongfan committed
func (rp *RestProtocol) Refer(url *common.URL) protocol.Invoker {
Patrick's avatar
Patrick committed
	// create rest_invoker
Patrick's avatar
Patrick committed
	var requestTimeout = config.GetConsumerConfig().RequestTimeout
	requestTimeoutStr := url.GetParam(constant.TIMEOUT_KEY, config.GetConsumerConfig().Request_Timeout)
	connectTimeout := config.GetConsumerConfig().ConnectTimeout
	if t, err := time.ParseDuration(requestTimeoutStr); err == nil {
		requestTimeout = t
	}
Patrick's avatar
Patrick committed
	id := url.GetParam(constant.BEAN_NAME_KEY, "")
	restServiceConfig := rest_config.GetRestConsumerServiceConfig(id)
Patrick's avatar
Patrick committed
	if restServiceConfig == nil {
		logger.Errorf("%s service doesn't has consumer config", url.Path)
		return nil
	}
Patrick's avatar
Patrick committed
	restOptions := client.RestOptions{RequestTimeout: requestTimeout, ConnectTimeout: connectTimeout}
Patrick's avatar
Patrick committed
	restClient := rp.getClient(restOptions, restServiceConfig.Client)
	invoker := NewRestInvoker(url, &restClient, restServiceConfig.RestMethodConfigsMap)
Patrick's avatar
Patrick committed
	rp.SetInvokers(invoker)
	return invoker
Patrick's avatar
Patrick committed
}

lihaowei's avatar
lihaowei committed
// nolint
haohongfan's avatar
haohongfan committed
func (rp *RestProtocol) getServer(url *common.URL, serverType string) server.RestServer {
	restServer, ok := rp.serverMap[url.Location]
Patrick's avatar
Patrick committed
	if ok {
		return restServer
	}
	_, ok = rp.ExporterMap().Load(url.ServiceKey())
Patrick's avatar
Patrick committed
		panic("[RestProtocol]" + url.ServiceKey() + "is not existing")
	}
	rp.serverLock.Lock()
Patrick's avatar
Patrick committed
	defer rp.serverLock.Unlock()
Patrick's avatar
Patrick committed
	restServer, ok = rp.serverMap[url.Location]
Patrick's avatar
Patrick committed
	if ok {
		return restServer
Patrick's avatar
Patrick committed
	restServer = extension.GetNewRestServer(serverType)
	restServer.Start(url)
	rp.serverMap[url.Location] = restServer
lihaowei's avatar
lihaowei committed
// nolint
Patrick's avatar
Patrick committed
func (rp *RestProtocol) getClient(restOptions client.RestOptions, clientType string) client.RestClient {
	restClient, ok := rp.clientMap[restOptions]
Patrick's avatar
Patrick committed
	if ok {
		return restClient
	}
	rp.clientLock.Lock()
Patrick's avatar
Patrick committed
	defer rp.clientLock.Unlock()
Patrick's avatar
Patrick committed
	restClient, ok = rp.clientMap[restOptions]
Patrick's avatar
Patrick committed
	if ok {
		return restClient
Patrick's avatar
Patrick committed
	restClient = extension.GetNewRestClient(clientType, &restOptions)
	rp.clientMap[restOptions] = restClient
lihaowei's avatar
lihaowei committed
// Destroy destroy rest service
Patrick's avatar
Patrick committed
func (rp *RestProtocol) Destroy() {
	// destroy rest_server
Patrick's avatar
Patrick committed
	rp.BaseProtocol.Destroy()
haohongfan's avatar
haohongfan committed
	for key, tmpServer := range rp.serverMap {
		tmpServer.Destroy()
		delete(rp.serverMap, key)
	}
	for key := range rp.clientMap {
		delete(rp.clientMap, key)
	}
Patrick's avatar
Patrick committed
}

lihaowei's avatar
lihaowei committed
// GetRestProtocol get a rest protocol
Patrick's avatar
Patrick committed
func GetRestProtocol() protocol.Protocol {
	if restProtocol == nil {
		restProtocol = NewRestProtocol()
	}
	return restProtocol
}