73 Star 43 Fork 8

bdware/doip-sdk

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README
MulanPSL-2.0

一、项目背景

1.DOA

数字对象架构(Digital Object Architecture, DOA)是现有Internet体系结构的一个逻辑扩展,它支持不同系统之间的数据互操作需求,而不仅仅是将数字形式的信息从Internet的一个位置传送到另一个位置。数字对象体系结构中的基本元素是数字对象(Digital Object),是对任意信息系统数据资源的统一抽象。数字对象分为四个部分:标识、元数据、状态数据以及实体。其中,标识永久且唯一的指向一个数字对象,是数字对象永久不变的属性;元数据是数字对象的描述信息,用于数字对象的检索和发现;状态数据包含数字对象当前位置、访问入口、访问方式等信息,用于数字对象的定位和访问;实体则是数字对象所包含的实际内容,可以是任何比特序列或一系列比特序列的集合。标识和状态数据的分离也使得数字对象的标识不在与数字对象的访问入口紧耦合,使得无论是否在互联网环境中,数字对象都可以被共享、访问,进而实现普适环境下的信息系统互操作。

DO是对互联网资源的抽象,DO代表互联网中有意义或者是有价值的资源。DO的表现形式可以是一个比特序列,或者是多个比特序列的集合;也可以是一个对外提供接口的程序。就像互联网中每一个Host都有一个IP地址作为标识一样,在DOA中每个DO同样有一个标识,用于对这个DO进行唯一的识别,这个标识叫做DOID。

DOA中有两个基本协议:标识/解析协议IRP(Identifier/Resolution Protocol)和数字对象接口协议DOIP(Digital Object Interface Protocol)。DOA中有三个基本的组成部分,分别是标识/解析系统(Identifier/Resolution System)负责DO的标识和解析、仓库系统(Repository System)负责DO的存储和访问、以及注册系统负责DO元数据的注册和DO的搜索(Registry System)。

2.DOIP

DOIP协议规定了客户端和数字对象进行交互的标准方式。数字对象服务,即DOIP服务,负责管理数字对象。同时,DOIP服务本身也可以视为一种数字对象,具有唯一的可解析的标识,并且可以基于DOIP服务访问其具体内容。DOIP协议使用IRP协议来解析和分配协议中所提到的各种标识。标识的最大长度可以随着时间变化,初始条件下,DOIP中标识的最大位数是4096位。

DOIP协议是应用层协议,规定了与数字对象管理、访问相关的语法和语义,其底层需要基于网络通讯协议来传递DOIP消息。DOIP 2.0 版本协议基于TLS协议传递DOIP消息,而在DOIP 2.1 版本中定义了一种新的消息格式,可以对消息的顺序性、完整性和安全性提供保障。因此,DOIP消息可以通过某些不可靠的通信协议(如UDP)进行传输。客户端可以根据DOIPServiceInfo中定义的字段来选择合适的通信协议。

在安全性保障方面,DOIP 2.0 版协议提供了一种基于PKI的安全性保障,通过CA证书验证客户端和服务端的身份信息,以及客户端和服务端的通讯加密。DOIP 2.1 版本协议则新增了一种基于标识解析系统的身份验证和安全性保障机制。每个用户均会被分配一个DOID作为身份标识,根据用户的DOID可以解析到用户的公钥信息,根据公钥信息即可验证用户的身份。默认情况下,公钥会被序列化为JWK的格式。

类型是每个DO的必要属性之一,类型的重要功能之一就是能使DOIP服务识别目标DO所支持的操作。DOIP中定义了一些基本类型,并支持对基本类型的扩展,或者创建新的类型。类型同样拥有一个DOID,并且可以通过IRP协议解析其对应的标识记录。扩展类型及新增类型由专业领域的组织或公司来负责在其领域中的类型创建,其标识记录中描述该类型的语义、结构以及其他的一些没有在DOIP中定义的细节。

二、项目结构

本项目是DOIP协议的软件开发套件SDK,可以基于本SDK实现DOIP Client和DOIP Server(DO Repository/Registry)。 项目整体功能模块如图所示,主要包括核心层和端点层两部分。

1.核心层

协议的编解码器,在src/main/codec目录: 负责对数字对象进行序列化编解码,以及对在通信协议中传输的DoipMessage进行编、解码操作。

2.端点层

协议端点的开发框架,在src/main/endpoint目录: 提供服务器和客户端的开发接口,可以方便的实现基于不同传输协议下的服务器和客户端软件。 当前SDK支持使用 udp、tcp、tls、websocket 等传输协议,可参考:src/test/java/org.bdware.doip.endpoint包内的client与server的写法。

三、使用前的准备

1.gradle.properties

项目编译前,需要在根目录下新建一个配置文件,文件名为gradle.properties,复制以下内容到文件内:

NEXUS_USERNAME=abc
NEXUS_PASSWORD=def
signing.keyId=ghi
signing.password=jkl
signing.secretKeyRingFile=mno

2.生成JWK密钥

DOIP Client和Server基于公私钥来进行身份验证和加密通讯,但并不限定公私钥的生成机制以及公钥的交换方式。 DOIP SDK默认采用JWX作为公私钥标准,JWK序列化密钥、JWS签名、JWE加解密。

有关JWX的相关介绍可以参考

通常情况下,用户的公私钥信息会作为用户的标识记录保存在标识解析系统中,在启用签名验证或加密时需要先将用户信息注册至IRS:

  1. 运行irs/src/main/java/org.bdware.irs.mocked.IRSMockMain,默认启动端口为10001,启动IRS
  2. 调用client/src/test/java/InternalIrpClientTest/updateUserHandleRecord 加载JWK并注册
  3. 然后可以通过用户标识,解析用户公钥

3.TLS加密证书(TLS通讯必须)

基于TLS协议的客户端与服务端,在启动时需要指定X509证书和私钥文件。相应证书、文件可以基于keytools工具生成。 请确保环境中安装有keytools工具,然后使用如下命令,生成服务端使用的私钥和证书。

  • 为Repository生成加密证书
keytool -genkey -keyalg RSA -keysize 2048 -validity 365 -keypass 123456 -keystore doip_service_repository.keystore -storepass 123456 -dname "UID=86.5000.470/doip.RepositoryTLSService"  
  • 为Registry生成加密证书
keytool -genkey -keyalg RSA -keysize 2048 -validity 365 -keypass 123456 -keystore doip_service_registry.keystore -storepass 123456 -dname "UID=86.5000.470/doip.RegistryTLSService"  

四、基于SDK开发数字对象仓库,提供DOIP服务:

数字对象仓库包含了对数字对象存储、管理等能力,需要结合具体的场景具体处理。 因此,DOIP SDK本身并不包含一个完整实现的数字对象仓库,但提供了相应的接口,开发者可以便捷的开发出符合自己需求的数字对象仓库。

1.实现服务器Handler

Handler是服务器处理请求的具体实现,不同的服务器应用之间的主要区别就在于使用了不同的Handler实现方式。 Handler每个方法的输入为接受到的DOIP请求消息,返回值为对应的DOIP响应消息。

不同的方法被赋予了不同的注解,在接收到DOIP消息时,会根据DOIPMessage.MessageHeader.HeaderParameter.operation判断其操作码调用相应的操作。 项目中对该接口的实现参考BDRepositoryHandler。对于继承的基本DOIP操作BasicOperations,不需要在实例化的方法上增加注解,在RequestHandlerImpl初始化时会根据其集成的方法逐层向上查找注解,直至找到RepositoryHandler和RegistryHandler方法上的注解。

缺省情况下,仓库系统的RepositoryHandler应该包含协议规定的六种基本操作,在SDK中表现为RepositoryHandler接口:

public interface RepositoryHandler {
    @Op(op = BasicOperations.Hello)
    DoipMessage handleHello(DoipMessage request);

    @Op(op = BasicOperations.ListOps)
    DoipMessage handleListOps(DoipMessage request);

    @Op(op = BasicOperations.Create)
    DoipMessage handleCreate(DoipMessage request);

    @Op(op = BasicOperations.Update)
    DoipMessage handleUpdate(DoipMessage request);

    @Op(op = BasicOperations.Delete)
    DoipMessage handleDelete(DoipMessage request);

    @Op(op = BasicOperations.Retrieve)
    DoipMessage handleRetrieve(DoipMessage request);
}

注册系统的RegistryHandler至少还需实现Search操作:

public interface RegistryHandler extends RepositoryHandler{  
    @Op(op = BasicOperations.Search)  
    DoipMessage handleSearch(DoipMessage request);  
}

SDK为开发者提供了RepositoryHandlerBase类和RegistryHandlerBase类做为开发仓库系统和注册系统Handler的基类,包含一些有助于开发的工具方法。 开发者可以通过继承基类来便捷的开发服务器的Handler。

2.配置服务器信息

服务器配置信息DoipServiceInfo主要包含以下参数:

class DoipServiceInfo{
    String id;
    String serviceDescription;
    String publicKey;
    String serviceName;
    int port;
    String ipAddress;
    String protocol;
    String protocolVersion;
    List<DoipListenerConfig> listenerInfos;
    String owner;
    String repoType;
}

其中 port、ipAddress、protocol、protocolVersion是为和DOIP v2.0协议兼容所设。DOIP v2.1协议使用ListenerInfo描述DOIP服务入口,包含url,protocolVersion两部分。其中url指明了服务入口所支持的协议以及地址。

class DoipListenerConfig{
    public String url;
    public String protocolVersion;
}

下面给出一个配置信息(json文件)的示例代码,其中的listenerInfos参数中包含了多个监听端口,并且不同端口支持使用不同的通信协议,目前SDK中内置了TLS、TCP、UDP以及WebSocket四种协议:

{
  "id": "localTest/doip.tcp",
  "serviceDescription": "testTCPServer",
  "publicKey": "{\"kty\":\"EC\",\"d\":\"VPvAXurYhEwCRbIuSCEPOaTyfUIbH6an4scA4BpdWCw\",\"use\":\"sig\",\"crv\":\"P-256\",\"kid\":\"86.5000.470\\/dou.TEST\",\"x\":\"IFVGcQ22vd7SEd1HsjcYuaLWUrfj4ochceom6YNCX4g\",\"y\":\"HSuB60fA_53vi4L30WiVQjouvAB0gSPAS8kf8Ny3RN0\"}",
  "serviceName": "testTCPServer",
  "listenerInfos": [
    {
      "url": "tcp://127.0.0.1:8001",
      "protocolVersion": "2.1"
    },
    {
      "url": "udp://127.0.0.1:8002",
      "protocolVersion": "2.1"
    }
  ],
  "owner": "86.5000.470/dou.TEST",
  "repoType": "registry"
}

可采用如下方法,直接将JSON格式的配置文件转换成DoipServiceInfo类型的配置信息:

    Reader infoStrReader = new FileReader("./config/conf.json");  
    DoipServiceInfo serviceInfo = new Gson().fromJson(infoStrReader,new TypeToken<DoipServiceInfo>(){}.getType());

3.生成服务器实例并启动

SDK为开发者提供了DoipServerImpl类作为开发服务器的模板类,开发者只需要使用DoipServiceInfo类型的配置信息即可生成服务器:

DoipServer server = new DoipServerImpl(DoipServiceInfo serviceInfo);

随后,通过DoipServer.setHandler方法,设置处理逻辑

server.setRepositoryHandler(RepositoryHandler handler);

启动服务器:

server.start();

服务器会根据DoipServiceInfo.listenerInfos,启动一个或多个监听,接受DOIP请求,请求会交由相应的Handler方法处理,并返回响应消息。

五、基于DOIP SDK开发DOIP客户端:

DOIP SDK提供了以及DoipClient接口以及缺省接口实现DoipClientImpl,访问目标仓库节点的DOIP服务。

public interface DoipClient {
    @Op(op = BasicOperations.Hello)
    void hello(String id, DoipMessageCallback cb);

    @Op(op = BasicOperations.ListOps)
    void listOperations(String id, DoipMessageCallback cb);

    @Op(op = BasicOperations.Retrieve)
    void retrieve(String id, String element, boolean includeElementData, DoipMessageCallback cb);

    @Op(op = BasicOperations.Create)
    void create(String targetDoipService, DigitalObject digitalObject, DoipMessageCallback cb);

    @Op(op = BasicOperations.Update)
    void update(DigitalObject digitalObject, DoipMessageCallback cb);

    @Op(op = BasicOperations.Delete)
    void delete(String id, DoipMessageCallback cb);

    @Op(op = BasicOperations.Search)
    void search(String id, SearchParameter sp, DoipMessageCallback cb);
}

1.生成客户端配置信息

客户端配置信息ClientConfig主要包含以下参数:

class ClientConfig{
    String url;                 //目标DOIP服务地址
    String protocolVersion;     //采用的DOIP协议版本
}

2.连接目标DOIP服务

以下是生成一个客户端并配置客户端信息的示例代码,默认情况下协议版本为V2.1:

        String targetDoipService = "udp://127.0.0.1:21042/";
        DoipClientImpl Client = new DoipClientImpl();
        Client.connect(ClientConfig.fromUrl(address));

3.访问目标DOIP服务并通过回调函数获取响应结果

DOIPClient通过回调函数DoipMessageCallback异步处理返回的消息,开发者需要实现DoipMessageCallback中的onResult方法,具体处理响应消息:

public interface DoipMessageCallback {
    void onResult(DoipMessage msg);
}

一个简单的访问示例入下所示,方法调用DoipClient.retrieve接口,向目标服务器发送了检索DO的请求(Retrieve):

public static void retrieve(String DOID) throws InterruptedException {
    String targetDoipService = "udp://127.0.0.1:21042/";
    DoipClientImpl Client = new DoipClientImpl();
    Client.connect(ClientConfig.fromUrl(address));
    boolean flag = true;
    client.retrieve(DOID,"",false, msg -> {
        try {
            flag = false;
            DigitalObject  ret_DO = msg.body.getDataAsDigitalObject();
            System.out.println(new Gson().toJson(msg.body.getDataAsDigitalObject()));
        } catch (DoDecodeException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    });
    while(flag){
        System.out.println("Wait For Response");
        Thread.sleep(5000);
    }
}

六、扩展DOIP SDK

1. 扩展DOIP操作

除了DOIP的7个基本操作之外,DOIP同样支持方法的扩展,但需要为扩展的方法增加注解以匹配新的操作码。扩展操作码的注解形式可参见如下代码:

public class BDRegistryHandler extends RegistryHandlerBase {
    /*
        .....
    */
    @Op(op = BasicOperations.Extension,name = "Op.Join")
    public DoipMessage handleJoin(DoipMessage request){
            if(request.header.parameters.attributes == null ||request.header.parameters.attributes.get("repoID")== null){
                logger.info("invalid join request: repoID not found");
                return replyStringWithStatus(request, "invalid join request: repoID not found.", DoipResponseCode.Invalid);
            }
            String repoID = request.header.parameters.attributes.get("repoID").getAsString();
            String repoUrl = request.header.parameters.attributes.get("repoUrl").getAsString();
            inRegs.put(repoID,repoUrl);
            saveRegFederation();
            return replyString(request,"success");
        }
    /*
        .....
    */
}

上述例子中BDRegistryHandler实现了RegistryHandler接口,除了实现基础的7个DOIP操作外还扩展实现了Join操作。 以Join方法为例,通过为handleJoin方法添加注解@Op(op = BasicOperations.Extension,name = "Op.Join") 其中op代表此方法为扩展的方法,name即为需要匹配的操作码。

通过扩展方法,BDRegistryHandler可以处理DOIP消息中operation为Op.Join的消息,

2. 扩展新的通讯协议

DOIP协议底层可以基于任意的通讯协议传递消息,本项目基于Netty实现了TCP,UDP,TLS以及Websocket协议,开发人员也可以结合实际需求扩展其他通讯协议。

基于新通讯协议的DOIP需要实现DOIPListener和DOIPClientChannel两个接口,分别用于服务端(Repository/Registry)和客户端。

public interface DoipListener {
    void start();
    void stop();
    void setRequestHandler(DoipRequestHandler handler);
}
public interface DoipClientChannel {
    void sendMessage(DoipMessage request, DoipMessageCallback callback);

    void close();

    void connect(String url) throws URISyntaxException, InterruptedException;

    boolean isConnected();
}

然后分别通过DoipListenerGenerator.addListener和DoipClientChannelGenerator.addClientChannel方法动态配置扩展通讯协议。 服务端和客户端在启动时会根据url的schema选择相应的Listener/ClientChannel连接。

一个扩展的基于Bluetooth协议的DOIP可参见Android DOIP Repository,其中BlueToothDoipListener即为Bluetooth协议实现。

客户端实现参考仓库Android DOIP Client,其中BlueToothDoipClient实现了DoipClientChannel方法。

七、相关协议

木兰宽松许可证, 第2版 木兰宽松许可证, 第2版 2020年1月 http://license.coscl.org.cn/MulanPSL2 您对“软件”的复制、使用、修改及分发受木兰宽松许可证,第2版(“本许可证”)的如下条款的约束: 0. 定义 “软件”是指由“贡献”构成的许可在“本许可证”下的程序和相关文档的集合。 “贡献”是指由任一“贡献者”许可在“本许可证”下的受版权法保护的作品。 “贡献者”是指将受版权法保护的作品许可在“本许可证”下的自然人或“法人实体”。 “法人实体”是指提交贡献的机构及其“关联实体”。 “关联实体”是指,对“本许可证”下的行为方而言,控制、受控制或与其共同受控制的机构,此处的控制是指有受控方或共同受控方至少50%直接或间接的投票权、资金或其他有价证券。 1. 授予版权许可 每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的版权许可,您可以复制、使用、修改、分发其“贡献”,不论修改与否。 2. 授予专利许可 每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的(根据本条规定撤销除外)专利许可,供您制造、委托制造、使用、许诺销售、销售、进口其“贡献”或以其他方式转移其“贡献”。前述专利许可仅限于“贡献者”现在或将来拥有或控制的其“贡献”本身或其“贡献”与许可“贡献”时的“软件”结合而将必然会侵犯的专利权利要求,不包括对“贡献”的修改或包含“贡献”的其他结合。如果您或您的“关联实体”直接或间接地,就“软件”或其中的“贡献”对任何人发起专利侵权诉讼(包括反诉或交叉诉讼)或其他专利维权行动,指控其侵犯专利权,则“本许可证”授予您对“软件”的专利许可自您提起诉讼或发起维权行动之日终止。 3. 无商标许可 “本许可证”不提供对“贡献者”的商品名称、商标、服务标志或产品名称的商标许可,但您为满足第4条规定的声明义务而必须使用除外。 4. 分发限制 您可以在任何媒介中将“软件”以源程序形式或可执行形式重新分发,不论修改与否,但您必须向接收者提供“本许可证”的副本,并保留“软件”中的版权、商标、专利及免责声明。 5. 免责声明与责任限制 “软件”及其中的“贡献”在提供时不带任何明示或默示的担保。在任何情况下,“贡献者”或版权所有者不对任何人因使用“软件”或其中的“贡献”而引发的任何直接或间接损失承担责任,不论因何种原因导致或者基于何种法律理论,即使其曾被建议有此种损失的可能性。 6. 语言 “本许可证”以中英文双语表述,中英文版本具有同等法律效力。如果中英文版本存在任何冲突不一致,以中文版为准。 条款结束 Mulan Permissive Software License,Version 2 Mulan Permissive Software License,Version 2 (Mulan PSL v2) January 2020 http://license.coscl.org.cn/MulanPSL2 Your reproduction, use, modification and distribution of the Software shall be subject to Mulan PSL v2 (this License) with the following terms and conditions: 0. Definition Software means the program and related documents which are licensed under this License and comprise all Contribution(s). Contribution means the copyrightable work licensed by a particular Contributor under this License. Contributor means the Individual or Legal Entity who licenses its copyrightable work under this License. Legal Entity means the entity making a Contribution and all its Affiliates. Affiliates means entities that control, are controlled by, or are under common control with the acting entity under this License, ‘control’ means direct or indirect ownership of at least fifty percent (50%) of the voting power, capital or other securities of controlled or commonly controlled entity. 1. Grant of Copyright License Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable copyright license to reproduce, use, modify, or distribute its Contribution, with modification or not. 2. Grant of Patent License Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable (except for revocation under this Section) patent license to make, have made, use, offer for sale, sell, import or otherwise transfer its Contribution, where such patent license is only limited to the patent claims owned or controlled by such Contributor now or in future which will be necessarily infringed by its Contribution alone, or by combination of the Contribution with the Software to which the Contribution was contributed. The patent license shall not apply to any modification of the Contribution, and any other combination which includes the Contribution. If you or your Affiliates directly or indirectly institute patent litigation (including a cross claim or counterclaim in a litigation) or other patent enforcement activities against any individual or entity by alleging that the Software or any Contribution in it infringes patents, then any patent license granted to you under this License for the Software shall terminate as of the date such litigation or activity is filed or taken. 3. No Trademark License No trademark license is granted to use the trade names, trademarks, service marks, or product names of Contributor, except as required to fulfill notice requirements in Section 4. 4. Distribution Restriction You may distribute the Software in any medium with or without modification, whether in source or executable forms, provided that you provide recipients with a copy of this License and retain copyright, patent, trademark and disclaimer statements in the Software. 5. Disclaimer of Warranty and Limitation of Liability THE SOFTWARE AND CONTRIBUTION IN IT ARE PROVIDED WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED. IN NO EVENT SHALL ANY CONTRIBUTOR OR COPYRIGHT HOLDER BE LIABLE TO YOU FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO ANY DIRECT, OR INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING FROM YOUR USE OR INABILITY TO USE THE SOFTWARE OR THE CONTRIBUTION IN IT, NO MATTER HOW IT’S CAUSED OR BASED ON WHICH LEGAL THEORY, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 6. Language THIS LICENSE IS WRITTEN IN BOTH CHINESE AND ENGLISH, AND THE CHINESE VERSION AND ENGLISH VERSION SHALL HAVE THE SAME LEGAL EFFECT. IN THE CASE OF DIVERGENCE BETWEEN THE CHINESE AND ENGLISH VERSIONS, THE CHINESE VERSION SHALL PREVAIL. END OF THE TERMS AND CONDITIONS How to Apply the Mulan Permissive Software License,Version 2 (Mulan PSL v2) to Your Software To apply the Mulan PSL v2 to your work, for easy identification by recipients, you are suggested to complete following three steps: i Fill in the blanks in following statement, including insert your software name, the year of the first publication of your software, and your name identified as the copyright owner; ii Create a file named “LICENSE” which contains the whole context of this License in the first directory of your software package; iii Attach the statement to the appropriate annotated syntax at the beginning of each source file. Copyright (c) [2021] [Peking University] [BDWare doip sdk] is licensed under Mulan PSL v2. You can use this software according to the terms and conditions of the Mulan PSL v2. You may obtain a copy of Mulan PSL v2 at: http://license.coscl.org.cn/MulanPSL2 THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. See the Mulan PSL v2 for more details.

简介

Doip-SDK包括以下两个部分: 1.协议的编解码器,在src/main/codec目录 2.协议的端点开发框架,在src/main/endpoint 展开 收起
Java 等 5 种语言
MulanPSL-2.0
取消

发行版 (1)

全部

贡献者

全部

近期动态

加载更多
不能加载更多了
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Java
1
https://gitee.com/BDWare/doip-sdk.git
git@gitee.com:BDWare/doip-sdk.git
BDWare
doip-sdk
doip-sdk
master

搜索帮助

Dd8185d8 1850385 E526c682 1850385