All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.bimface.sdk.client.BdfsClient Maven / Gradle / Ivy

The newest version!
package com.bimface.sdk.client;

import com.bimface.bdfs.bean.*;
import com.bimface.bdfs.bean.dto.*;
import com.bimface.bdfs.bean.dto.v1.FileItemDTOV1;
import com.bimface.bdfs.bean.dto.v1.multipartupload.*;
import com.bimface.bean.GeneralResponse;
import com.bimface.exception.BimfaceException;
import com.bimface.sdk.bean.response.AccessTokenBean;
import com.bimface.sdk.bean.response.FileItemUploadStatusBean;
import com.bimface.bdfs.enums.ProjectType;
import com.bimface.http.BimfaceResponseChecker;
import com.bimface.page.PagedList;
import com.bimface.sdk.bean.request.FileItemQueryRequest;
import com.bimface.sdk.bean.request.ProjectCreateRequest;
import com.bimface.sdk.config.Config;
import com.bimface.sdk.interfaces.BdfsInterface;
import com.glodon.paas.foundation.restclient.RESTCallHelper;
import com.glodon.paas.foundation.restclient.RESTClientBuilder;
import com.glodon.paas.foundation.restclient.RESTResponse;
import com.glodon.paas.foundation.restclient.RESTStreamRequestBody;
import com.google.gson.JsonDeserializer;
import okhttp3.RequestBody;
import org.apache.commons.lang3.tuple.Pair;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import retrofit2.Call;
import com.bimface.sdk.bean.request.CreateFolderRequest;
import retrofit2.http.*;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

/**
 * Created by tangj-i on 2023/3/27.
 */
public class BdfsClient extends AbstractClient {
    private final static Logger logger = LoggerFactory.getLogger(BdfsClient.class);

    private BdfsInterface bdfsClient;

    private static BdfsClient instance;

    public static synchronized BdfsClient getBdfsClient(String bdfsBaseUrl) {
        return getBdfsClient(bdfsBaseUrl, null);
    }

    public static synchronized BdfsClient getBdfsClient(String bdfsBaseUrl, Config config) {
        return instance != null ? instance : new BdfsClient(bdfsBaseUrl, config);
    }

    private BdfsClient(String bdfsBaseUrl, Config config) {
        RESTClientBuilder builder = new RESTClientBuilder()
                .serviceBaseUrl(bdfsBaseUrl)
                .responseChecker(new BimfaceResponseChecker());

        // 如果设置config,则使用rest client的默认配置
        if (config != null) {
            builder.timeoutMilli(config.getConnectTimeout(), config.getWriteTimeout(), config.getReadTimeout());
        }

        if (logger.isDebugEnabled()) {
            builder.enableHttpLoggingInterceptor();
        }

        this.bdfsClient = builder.build(BdfsInterface.class);
    }

    private Date _convertToCST(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR, calendar.get(Calendar.HOUR) + 8);
        return calendar.getTime();
    }


    /**
     * 获取hub列表
     *
     * @param name         hub名称
     * @param tenantCode   租户标识
     * @param info         描述信息
     * @param dateTimeFrom 开始时间
     * @param dateTimeTo   结束时间
     * @param accessToken  accessToken
     * @return
     */
    public List getHubList(String name, String tenantCode, String info, String dateTimeFrom, String dateTimeTo, String accessToken) {
        accessToken = validToken(accessToken);
        return RESTCallHelper.executeCall(bdfsClient.getHubList(name, tenantCode, info, dateTimeFrom, dateTimeTo, accessToken));
    }

    /**
     * 获取Hub Meta信息
     *
     * @param hubId       hubId
     * @param accessToken accessToken
     * @return 单个Hub
     */
    public HubDTO getHubMeta(Long hubId, String accessToken) {
        accessToken = validToken(accessToken);
        return RESTCallHelper.executeCall(bdfsClient.getHubMeta(hubId, accessToken));
    }

    /**
     * 创建项目
     *
     * @param hubId
     * @param request     项目目创建请求
     * @param accessToken accessToken
     * @return
     */
    public ProjectDTO createProject(String hubId, ProjectCreateRequest request, String accessToken) {
        accessToken = validToken(accessToken);
        Call> viewCall = bdfsClient.createProject(hubId, request, accessToken);
        return RESTCallHelper.executeCall(viewCall);
    }

    /**
     * 获取项目列表
     *
     * @param hubId
     * @param name           项目名称
     * @param useFuzzySearch 是否使用模糊查询
     * @param accessToken    accessToken
     * @return
     */
    public List getProjectList(String hubId, String name, Boolean useFuzzySearch, String accessToken) {
        accessToken = validToken(accessToken);
        Call>> viewCall = bdfsClient.getProjectList(hubId, name, useFuzzySearch, accessToken);
        return RESTCallHelper.executeCall(viewCall);
    }

    /**
     * 获取项目信息
     *
     * @param hubId     hubId
     * @param projectId 项目Id
     * @return
     */
    public ProjectDTO getProjectMeta(String hubId, String projectId, String accessToken) {
        accessToken = validToken(accessToken);
        return RESTCallHelper.executeCall(bdfsClient.getProjectMeta(hubId, projectId, accessToken));
    }

    /**
     * 删除项目
     *
     * @param hubId     hubId
     * @param projectId 项目Id
     * @return
     */
    public ProjectDTO deleteProject(String hubId, String projectId, String accessToken) {
        accessToken = validToken(accessToken);
        return RESTCallHelper.executeCall(bdfsClient.deleteProject(hubId, projectId, accessToken));
    }

    /**
     * 更新项目信息
     *
     * @param hubId            hubId
     * @param projectId        项目Id
     * @param updateProjectReq 更新项目信息请求体
     * @return
     */
    public ProjectDTO updateProject(String hubId, String projectId, UpdateProjectRequest updateProjectReq, String accessToken) {
        accessToken = validToken(accessToken);
        return RESTCallHelper.executeCall(bdfsClient.updateProject(hubId, projectId, updateProjectReq, accessToken));
    }

    /**
     * 获取项目根文件夹信息
     *
     * @param hubId     hubId
     * @param projectId 项目Id
     * @return
     */
    public FileItemWithPathDTO getProjectRootFolderInfo(String hubId, String projectId, String accessToken) {
        accessToken = validToken(accessToken);
        return RESTCallHelper.executeCall(bdfsClient.getProjectRootFolderInfo(hubId, projectId, accessToken));
    }

    /**
     * 指定目录创建文件夹
     */
    public FileItemDTO createFolder(String projectId, CreateFolderRequest createFolderRequest, String accessToken) {
        accessToken = validToken(accessToken);
        return RESTCallHelper.executeCall(bdfsClient.createFolder(projectId, createFolderRequest, accessToken));
    }

    /**
     * 获取文件夹信息
     */
    public FileItemDTO getFolder(String projectId, String folderId, String path, String accessToken) {
        accessToken = validToken(accessToken);
        return RESTCallHelper.executeCall(bdfsClient.getFolder(projectId, folderId, path, accessToken));
    }

    /**
     * 获取children列表(不包含itemSource)
     *
     * @param projectId            项目ID
     * @param fileItemQueryRequest
     * @param accessToken          accessToken
     * @return
     */
    public PagedList getChildrenFileItems(String projectId, FileItemQueryRequest fileItemQueryRequest, String accessToken) {
        accessToken = validToken(accessToken);
        fileItemQueryRequest.setWithItemSource(false);
        return RESTCallHelper.executeCall(bdfsClient.getChildrenFileItems(projectId, fileItemQueryRequest, accessToken));
    }


    /**
     * 根据folderId 获取文件夹路径
     *
     * @param projectId   项目ID
     * @param folderId    文件夹ID
     * @param accessToken accessToken
     * @return
     */
    public String getFolderPathById(String projectId, String folderId, String accessToken) {
        accessToken = validToken(accessToken);
        return RESTCallHelper.executeCall(bdfsClient.getFolderPathById(projectId, folderId, accessToken));
    }

    /**
     * 获取父文件夹
     *
     * @param projectId
     * @param folderId
     * @param accessToken accessToken
     * @return
     */
    public FileItemDTO getParent(String projectId, String folderId, String accessToken) {
        accessToken = validToken(accessToken);
        return RESTCallHelper.executeCall(bdfsClient.getParent(projectId, folderId, accessToken));
    }

    /**
     * 文件夹重命名
     * 根据folderId(path)更新文件夹
     *
     * @param projectId       项目id
     * @param updateFolderReq 更新文件夹请求体
     * @return
     */
    public FileItemDTO updateFolder(String projectId, UpdateFolderRequest updateFolderReq, String accessToken) {
        accessToken = validToken(accessToken);
        return RESTCallHelper.executeCall(bdfsClient.updateFolder(projectId, updateFolderReq, accessToken));
    }

    /**
     * 删除文件夹
     * 根据folderId(path)删除文件夹
     *
     * @param projectId 项目id
     * @param folderId  文件夹id(folderId和path,必须二选一填入)
     * @param path      文件夹路径,使用URL编码(UTF-8),最多256个字符(folderId和path,必须二选一填入)
     * @return
     */
    public String deleteFolder(String projectId, String folderId, String path, String accessToken) {
        accessToken = validToken(accessToken);
        return RESTCallHelper.executeCall(bdfsClient.deleteFolder(projectId, folderId, path, accessToken));
    }

    /**
     * 上传文件流
     *
     * @param fileIn      文件流
     * @param projectId   项目id
     * @param parentId    父文件夹id
     * @param parentPath  父文件夹路径
     * @param name        文件名称
     * @param length      文件大小
     * @param sourceId    源文件id
     * @param accessToken accessToken
     * @return
     */
    public FileItemDTO uploadFileItem(InputStream fileIn, String projectId, String parentId, String parentPath, String name, Long length, String sourceId, String accessToken) {
        accessToken = validToken(accessToken);
        Pair pair = getInputStreamAndLength(fileIn, length);
        RequestBody requestBody = RESTStreamRequestBody.create(okhttp3.MediaType.parse("application/octet-stream"), pair.getRight(), pair.getLeft());
        return RESTCallHelper.executeCall(bdfsClient.uploadFileItem(projectId, parentId, parentPath, name, sourceId, length, requestBody, accessToken));
    }

    /**
     * 指定外部文件url方式上传
     *
     * @param projectId   项目ID
     * @param parentId    父文件夹Id
     * @param parentPath  父文件夹路径
     * @param name        文件名称
     * @param sourceId    调用方的文件源ID,不能重复
     * @param url         sourceUrl
     * @param etag        文件etag
     * @param maxLength   maxLength
     * @param accessToken accessToken
     * @return
     */
    public FileItemDTO uploadByUrl(String projectId, String parentId, String parentPath, String name, String sourceId, String url, String etag, Long maxLength, String accessToken) {
        accessToken = validToken(accessToken);
        return RESTCallHelper.executeCall(bdfsClient.uploadByUrl(projectId, parentId, parentPath, name, sourceId, url, etag, maxLength, accessToken));
    }

    /**
     * 创建追加文件
     *
     * @param projectId  项目ID
     * @param parentId   父文件夹Id
     * @param parentPath 父文件夹路径
     * @param name       文件名称
     * @param length     文件流的长度
     * @param sourceId   调用方的文件源ID,不能重复
     * @return
     */
    public FileItemAppendFileDTO createAppendFile(String projectId, String parentId, String parentPath, String name, Long length, String sourceId, String accessToken) {
        accessToken = validToken(accessToken);
        return RESTCallHelper.executeCall(bdfsClient.createAppendFile(projectId, parentId, parentPath, name, length, sourceId, accessToken));
    }

    /**
     * 获取追加文件信息
     * 获取FileItemAppendFile
     *
     * @param projectId    项目ID
     * @param appendFileId 追加上传ID
     * @return
     */
    public FileItemAppendFileDTO getAppendFile(String projectId, String appendFileId, String accessToken) {
        accessToken = validToken(accessToken);
        return RESTCallHelper.executeCall(bdfsClient.getAppendFile(projectId, appendFileId, accessToken));
    }

    /**
     * 追加上传文件
     *
     * @param projectId    项目ID
     * @param appendFileId 父文件夹Id
     * @param position     父文件夹路径
     * @return
     */
    public FileItemAppendFileDTO appendUpload(InputStream fileIn, String projectId, String appendFileId, String position, String accessToken) {
        accessToken = validToken(accessToken);
        Pair pair = getInputStreamAndLength(fileIn, null);
        RequestBody requestBody = RESTStreamRequestBody.create(okhttp3.MediaType.parse("application/octet-stream"), pair.getRight(), pair.getLeft());
        return RESTCallHelper.executeCall(bdfsClient.appendUpload(projectId, appendFileId, position, requestBody, accessToken));
    }

    /**
     * 复制文件
     *
     * @param projectId       项目ID
     * @param copyFileRequest 复制文件请求体
     * @return
     */
    public List copyFile(String projectId, CopyFileRequest copyFileRequest, String accessToken) {
        accessToken = validToken(accessToken);
        return RESTCallHelper.executeCall(bdfsClient.copyFile(projectId, copyFileRequest, accessToken));
    }

    /**
     * 获取文件直传的policy凭证
     * 获取上传file的policy
     *
     * @param projectId  项目ID
     * @param parentId   父文件ID
     * @param parentPath 父文件路径
     * @param name       文件名称
     * @param sourceId   调用方的文件源ID
     * @param maxLength  文件流的长度
     * @return
     */
    public UploadPolicyResponse getFileItemPolicy(String projectId, String parentId, String parentPath, String name, String sourceId, Long maxLength, String accessToken) {
        accessToken = validToken(accessToken);
        return RESTCallHelper.executeCall(bdfsClient.getFileItemPolicy(projectId, parentId, parentPath, name, sourceId, maxLength, accessToken));
    }

    private Pair getInputStreamAndLength(InputStream fileIn, Long size) {
        //1.若传了size,则以传的大小为准
        if (size != null) {
            return Pair.of(fileIn, size);
        }

        try {
            //2.若是FileInputStream,则直接读取available
            if (fileIn instanceof FileInputStream) {
                return Pair.of(fileIn, (long) fileIn.available());
            }
            //3.若是来自网络流,则直接返回-1
            return Pair.of(fileIn, -1L);
        } catch (IOException e) {
            return Pair.of(fileIn, size);
        }
    }

    /**
     * 获取文件信息
     *
     * @param projectId      项目id
     * @param fileItemId     文件id
     * @param path           文件路径
     * @param withItemSource 是否携带fileItemSource信息
     * @param accessToken
     * @return
     */
    public FileItemDTO getFileItemMeta(String projectId, String fileItemId, String path, Boolean withItemSource, String accessToken) {
        accessToken = validToken(accessToken);
        return RESTCallHelper.executeCall(bdfsClient.getFileItemMeta(projectId, fileItemId, path, withItemSource, accessToken));
    }


    /**
     * 获取文件状态
     *
     * @param projectId   项目id
     * @param fileItemId  文件id
     * @param path        文件路径
     * @param accessToken accessToken
     * @return
     */
    public FileItemUploadStatusBean getFileItemStatus(String projectId, String fileItemId, String path, String accessToken) {
        accessToken = validToken(accessToken);
        return RESTCallHelper.executeCall(bdfsClient.getFileItemUploadStatus(projectId, fileItemId, path, accessToken));
    }

    /**
     * 获取文件下载签名URL
     *
     * @param projectId   项目id
     * @param fileItemId  文件id
     * @param path        文件路径
     * @param expireTime  过期时间
     * @param accessToken accessToken
     * @return
     */
    public String getDownloadURl(String projectId, String fileItemId, String path, Integer expireTime, String accessToken) {
        accessToken = validToken(accessToken);
        return RESTCallHelper.executeCall(bdfsClient.getFileItemSignedUrl(projectId, fileItemId, path, expireTime, accessToken));
    }

    /**
     * 获取文件路径
     * 根据fileItemId获取fileItemPath
     *
     * @param projectId  项目ID
     * @param fileItemId 文件ID
     * @return
     */
    public String getFileItemPathById(String projectId, String fileItemId, String accessToken) {
        accessToken = validToken(accessToken);
        return RESTCallHelper.executeCall(bdfsClient.getFileItemPathById(projectId, fileItemId, accessToken));
    }

    /**
     * 打包下载压缩文件
     *
     * @param projectId   项目ID
     * @param fileItemIds 文件ID
     * @return
     */
    public String downloadFiles(String projectId, List fileItemIds, String accessToken) {
        accessToken = validToken(accessToken);
        return RESTCallHelper.executeCall(bdfsClient.downloadFiles(projectId, fileItemIds, accessToken));
    }

    /**
     * 移动文件位置
     *
     * @param projectId       项目ID
     * @param moveFileRequest 移动文件请求体
     * @return
     */
    public List moveFile(String projectId, MoveFileRequest moveFileRequest, String accessToken) {
        accessToken = validToken(accessToken);
        return RESTCallHelper.executeCall(bdfsClient.moveFile(projectId, moveFileRequest, accessToken));
    }

    /**
     * 文件重命名
     *
     * @param projectId         项目ID
     * @param updateFileRequest 更新文件请求体
     * @return
     */
    public FileItemDTO fileRename(String projectId, UpdateFileRequest updateFileRequest, String accessToken) {
        accessToken = validToken(accessToken);
        return RESTCallHelper.executeCall(bdfsClient.fileRename(projectId, updateFileRequest, accessToken));
    }

    /**
     * 批量删除文件
     *
     * @param projectId   项目id
     * @param fileItemIds 文件id集合
     * @param accessToken accessToken
     */
    public void batchDeleteFileItems(String projectId, List fileItemIds, String accessToken) {
        accessToken = validToken(accessToken);
        RESTCallHelper.executeCall(bdfsClient.batchDeleteFileItems(projectId, fileItemIds, accessToken));
    }

    /**
     * 创建分片上传任务
     *
     * @param projectId                  项目id
     * @param initMultipartUploadRequest 初始化分片上传的请求体
     * @param accessToken                accessToken
     * @throws BimfaceException {@link BimfaceException}
     */
    public InitMultipartUploadDTO initMultipartUpload(@NotNull String projectId, @NotNull InitMultipartUploadRequest initMultipartUploadRequest, @NotNull String accessToken) {
        accessToken = validToken(accessToken);
        return RESTCallHelper.executeCall(bdfsClient.initMultipartUpload(projectId, initMultipartUploadRequest, accessToken));
    }

    /**
     * 获取分片上传url
     *
     * @param projectId                 项目 id
     * @param multipartSignedUrlRequest 获取分片的 signedUrl的请求体
     * @return 生成的 signed url
     */
    public String getMultipartSignedUrl(@NotNull String projectId, @NotNull MultipartSignedUrlRequest multipartSignedUrlRequest, @NotNull String accessToken) {
        accessToken = validToken(accessToken);
        return RESTCallHelper.executeCall(bdfsClient.getMultipartSignedUrl(projectId, multipartSignedUrlRequest, accessToken));
    }

    /**
     * 合并分片生成文件
     *
     * @param projectId                      项目 id
     * @param completeMultipartUploadRequest 完成分片上传的请求体
     * @return 返回生成的 FileItem
     */
    public FileItemDTOV1 completeMultiPartUpload(@NotNull String projectId,
                                                 @NotNull CompleteMultipartUploadRequest completeMultipartUploadRequest,
                                                 @NotNull String accessToken) {
        accessToken = validToken(accessToken);
        return RESTCallHelper.executeCall(bdfsClient.completeMultiPartUpload(projectId, completeMultipartUploadRequest, accessToken));
    }

    /**
     * 终止分片上传任务
     *
     * @param projectId                   项目 id
     * @param abortMultipartUploadRequest 终止分片上传的请求体
     * @return 提示信息
     */
    public String abortMultiPartUpload(@NotNull String projectId,
                                       @NotNull AbortMultipartUploadRequest abortMultipartUploadRequest,
                                       @NotNull String accessToken) {
        accessToken = validToken(accessToken);
        return RESTCallHelper.executeCall(bdfsClient.abortMultiPartUpload(projectId, abortMultipartUploadRequest, accessToken));
    }

    /**
     * 获取所有版本文件信息
     *
     * @param projectId  项目ID
     * @param fileItemId 文件Id
     * @param path       文件路径
     * @param pageNo     开始页码
     * @param pageSize   每页大小
     * @return PagedList
     */
    public PagedList getAllVersions(@NotNull String projectId,
                                                 @NotNull String fileItemId,
                                                 @NotNull String path,
                                                 Integer pageNo,
                                                 Integer pageSize,
                                                 @NotNull String accessToken) {
        accessToken = validToken(accessToken);
        return RESTCallHelper.executeCall(bdfsClient.getAllVersions(projectId, fileItemId, path, pageNo, pageSize, accessToken));
    }

    /**
     * 上传版本文件
     *
     * @param fileIn     文件流
     * @param projectId  项目ID
     * @param fileItemId 文件Id
     * @param path       文件路径
     * @param name       文件名称
     * @param length     文件长度
     * @param sourceId   调用方的文件源ID,不能重复
     * @return FileItemDTO
     */
    public FileItemDTO createVersion(@NotNull InputStream fileIn,
                                     @NotNull String projectId,
                                     @NotNull String fileItemId,
                                     String path,
                                     String name,
                                     Long length,
                                     String sourceId,
                                     @NotNull String accessToken) {
        accessToken = validToken(accessToken);
        Pair pair = getInputStreamAndLength(fileIn, length);
        RequestBody requestBody = RESTStreamRequestBody.create(okhttp3.MediaType.parse("application/octet-stream"), pair.getRight(), pair.getLeft());
        return RESTCallHelper.executeCall(bdfsClient.createVersion(projectId, fileItemId, path, name, length, sourceId, requestBody, accessToken));
    }

    /**
     * 获取新版本直传的policy凭证
     *
     * @param projectId  项目ID
     * @param fileItemId 文件Id
     * @param path       文件路径
     * @param name       文件名称
     * @param sourceId   调用方的文件源ID,不能重复
     * @param maxLength  文件流的长度
     * @return UploadPolicyResponse
     */
    public UploadPolicyResponse getFilePolicy(@NotNull String projectId,
                                              @NotNull String fileItemId,
                                              @NotNull String path,
                                              String name,
                                              String sourceId,
                                              Long maxLength,
                                              @NotNull String accessToken) {
        accessToken = validToken(accessToken);
        return RESTCallHelper.executeCall(bdfsClient.getFilePolicy(projectId, fileItemId, path, name, sourceId, maxLength, accessToken));
    }

    /**
     * 获取指定版本文件信息
     *
     * @param projectId      项目ID
     * @param fileId         文件版本Id
     * @param withFileSource 是否携带itemSource
     * @return FileItemDTO
     */
    public FileItemDTO getVersion(@NotNull String projectId,
                                  @NotNull String fileId,
                                  Boolean withFileSource,
                                  @NotNull String accessToken) {
        accessToken = validToken(accessToken);
        return RESTCallHelper.executeCall(bdfsClient.getVersion(projectId, fileId, withFileSource, accessToken));
    }

    /**
     * 下载指定版本文件
     *
     * @param projectId  项目ID
     * @param fileId     文件版本Id
     * @param expireTime 有限期,默认3600s
     * @return String
     */
    public String getVersionSignedUrl(@NotNull String projectId,
                                      @NotNull String fileId,
                                      Integer expireTime,
                                      @NotNull String accessToken) {
        accessToken = validToken(accessToken);
        return RESTCallHelper.executeCall(bdfsClient.getVersionSignedUrl(projectId, fileId, expireTime, accessToken));
    }

    /**
     * 删除指定版本文件
     *
     * @param projectId 项目ID
     * @param fileIds   文件版本Id
     * @return String
     */
    public String deleteVersion(@NotNull String projectId,
                                @NotNull List fileIds,
                                @NotNull String accessToken) throws BimfaceException {
        accessToken = validToken(accessToken);
        return RESTCallHelper.executeCall(bdfsClient.deleteVersion(projectId, fileIds, accessToken));
    }


    /**
     * 获取成功上传的分片列表
     * @param projectId 项目ID
     * @param id 分片上传ID
     * @param accessToken 访问令牌
     * @return 成功上传的分片列表
     */
    public MultipartUploadSuccessPartListDTO getSuccessUploadParts(@NotNull String projectId,
                                @NotNull String id,
                                @NotNull String accessToken) throws BimfaceException {
        accessToken = validToken(accessToken);
        return RESTCallHelper.executeCall(bdfsClient.getSuccessUploadParts(projectId,id,accessToken));
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy