git-proxy / src /services /repoApi.ts
github-actions[bot]
Update from GitHub Actions
15ff6c7
raw
history blame
9.03 kB
import router from '../router';
import { API_BASE_URL, getHeaders, handleResponse } from './util';
export interface Account {
owner: string;
repo: string;
ref: string;
type: "github" | "hf";
token: string;
}
export interface RepoContent {
name: string;
path: string;
sha: string;
size: number;
url: string;
html_url: string;
git_url: string;
download_url: string | null;
type: "file" | "dir";
content?: string;
encoding?: string;
}
// Base interface for repo operations
interface IRepoApi {
getContents(account: Account, path: string): Promise<RepoContent[]>;
getFileContent(account: Account, path: string): Promise<RepoContent>;
updateFile(account: Account, path: string, content: string, sha: string, message?: string): Promise<any>;
deleteFile(account: Account, path: string, sha: string, message?: string): Promise<any>;
createFile(account: Account, path: string, content: string, message?: string): Promise<any>;
}
// GitHub implementation
class GitHubRepoApi implements IRepoApi {
async getContents(account: Account, path: string = ''): Promise<RepoContent[]> {
const response = await fetch(
`${API_BASE_URL}/api/github/${account.owner}/${account.repo}/${path}?ref=${account.ref}`,
{
headers: {
Authorization: `Bearer ${account.token}`
}
}
);
return await handleResponse(response);
}
async getFileContent(account: Account, path: string): Promise<RepoContent> {
const response = await fetch(
`${API_BASE_URL}/api/github/${account.owner}/${account.repo}/${path}?ref=${account.ref}`,
{
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${account.token}`
}
}
);
return await handleResponse(response);
}
async updateFile(account: Account, path: string, content: string, sha: string, message?: string) {
const encoder = new TextEncoder();
const bytes = encoder.encode(content);
const base64Content = btoa(String.fromCharCode.apply(null, [...new Uint8Array(bytes)]));
const response = await fetch(
`${API_BASE_URL}/api/github/${account.owner}/${account.repo}/${path}`,
{
method: 'PUT',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${account.token}`
},
body: JSON.stringify({ branch: account.ref, content: base64Content, message, sha })
}
);
return handleResponse(response);
}
async deleteFile(account: Account, path: string, sha: string, message?: string) {
const response = await fetch(
`${API_BASE_URL}/api/github/${account.owner}/${account.repo}/${path}`,
{
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${account.token}`
},
body: JSON.stringify({ branch: account.ref, sha, message })
}
);
return handleResponse(response);
}
async createFile(account: Account, path: string, content: string, message?: string) {
const encoder = new TextEncoder();
const bytes = encoder.encode(content);
const base64Content = btoa(String.fromCharCode.apply(null, [...new Uint8Array(bytes)]));
const response = await fetch(
`${API_BASE_URL}/api/github/${account.owner}/${account.repo}/${path}`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${account.token}`
},
body: JSON.stringify({ branch: account.ref, content: base64Content, message })
}
);
return handleResponse(response);
}
}
// HuggingFace implementation
class HuggingFaceRepoApi implements IRepoApi {
async getContents(account: Account, path: string = ''): Promise<RepoContent[]> {
const response = await fetch(
`${API_BASE_URL}/api/hf/${account.owner}/${account.repo}/tree/${account.ref}/${path}`,
{
method: 'GET',
headers: {
Authorization: `Bearer ${account.token}`
}
}
);
let result = await handleResponse(response);
return result.map((item: any) => {
item.sha = item.oid;
item.name = item.path.split('/').pop() || '';
return item;
});
}
async getFileContent(account: Account, path: string): Promise<RepoContent> {
const response = await fetch(
`${API_BASE_URL}/api/hf/${account.owner}/${account.repo}/raw/${account.ref}/${path}`,
{
method: 'GET',
headers: {
Authorization: `Bearer ${account.token}`
}
}
);
if (response.status === 401) {
localStorage.removeItem('isAuthenticated');
localStorage.removeItem('token');
router.push('/login');
throw new Error('认证失败,请重新登录');
}
return {
content: await response.text(),
encoding: 'utf-8',
name: '',
path: path,
sha: '',
size: 0,
url: '',
html_url: '',
git_url: '',
download_url: null,
type: 'file'
};
}
async updateFile(account: Account, path: string, content: string, sha: string, message?: string) {
const response = await fetch(
`${API_BASE_URL}/api/hf/${account.owner}/${account.repo}/commit/${account.ref}/${path}`,
{
method: 'PUT',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${account.token}`
},
body: JSON.stringify({
"description": "",
"summary": message,
"files": [
{
"content": content,
"encoding": "utf-8",
"path": path
}
]
})
}
);
const result = await handleResponse(response);
return {
content: {
sha: result.commitOid
}
};
}
async deleteFile(account: Account, path: string, sha: string, message?: string) {
const response = await fetch(
`${API_BASE_URL}/api/hf/${account.owner}/${account.repo}/commit/${account.ref}/${path}`,
{
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${account.token}`
},
body: JSON.stringify({
"description": "",
"summary": message,
"deletedFiles": [
{
"path": path
}
]
})
}
);
return handleResponse(response);
}
async createFile(account: Account, path: string, content: string, message?: string) {
const response = await fetch(
`${API_BASE_URL}/api/hf/${account.owner}/${account.repo}/commit/${account.ref}/${path}`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${account.token}`
},
body: JSON.stringify({
"description": "",
"summary": message,
"files": [
{
"content": content,
"encoding": "utf-8",
"path": path
}
]
})
}
);
const result = await handleResponse(response);
return {
content: {
sha: result.commitOid
}
};
}
}
// Factory to get the appropriate repo API implementation
class RepoApiFactory {
private static githubInstance: GitHubRepoApi;
private static huggingFaceInstance: HuggingFaceRepoApi;
static getRepoApi(type: "github" | "hf"): IRepoApi {
switch (type) {
case "github":
if (!this.githubInstance) {
this.githubInstance = new GitHubRepoApi();
}
return this.githubInstance;
case "hf":
if (!this.huggingFaceInstance) {
this.huggingFaceInstance = new HuggingFaceRepoApi();
}
return this.huggingFaceInstance;
default:
throw new Error(`Unsupported repository type: ${type}`);
}
}
}
// Exported API object that uses the factory
export const repoApi = {
async getContents(account: Account, path: string = '') {
const api = RepoApiFactory.getRepoApi(account.type);
return api.getContents(account, path);
},
async getFileContent(account: Account, path: string): Promise<RepoContent> {
const api = RepoApiFactory.getRepoApi(account.type);
return api.getFileContent(account, path);
},
async updateFile(account: Account, path: string, content: string, sha: string, message?: string) {
const api = RepoApiFactory.getRepoApi(account.type);
return api.updateFile(account, path, content, sha, message);
},
async deleteFile(account: Account, path: string, sha: string, message?: string) {
const api = RepoApiFactory.getRepoApi(account.type);
return api.deleteFile(account, path, sha, message);
},
async createFile(account: Account, path: string, content: string, message?: string) {
const api = RepoApiFactory.getRepoApi(account.type);
return api.createFile(account, path, content, message);
}
};