-
Notifications
You must be signed in to change notification settings - Fork 997
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add api to serve files under repositories (#851)
* feat: add api to serve files under repositories * resolve comments * resolve comments * Update repositories.rs * Update lib.rs * resolve comment --------- Co-authored-by: Meng Zhang <[email protected]>
- Loading branch information
Showing
8 changed files
with
382 additions
and
3 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
# API Specs | ||
|
||
## Repository api: `/repositories` | ||
|
||
### Resolve | ||
|
||
Get file or directory content from local repositories | ||
|
||
**URL:** `/repositories/{name}/resolve/{path}` | ||
|
||
**Method:** `GET` | ||
|
||
**Request examples:** | ||
|
||
- Get directory content | ||
|
||
```shell | ||
curl --request GET \ | ||
--url http://localhost:8080/repositories/https_github.com_TabbyML_tabby.git/resolve/ | ||
|
||
curl --request GET \ | ||
--url http://localhost:9090/repositories/https_github.com_TabbyML_tabby.git/resolve/ee/tabby-webserver/ | ||
``` | ||
|
||
- Get file content | ||
|
||
```shell | ||
curl --request GET \ | ||
--url http://localhost:8080/repositories/https_github.com_TabbyML_tabby.git/resolve/package.json | ||
|
||
curl --request GET \ | ||
--url http://localhost:9090/repositories/https_github.com_TabbyML_tabby.git/resolve/ee/tabby-webserver/src/api.rs | ||
``` | ||
|
||
**Response examples:** | ||
|
||
- All directory query will return a list of string, with each string represents an entry under that directory. The `Content-Type` for directory query is `application/vnd.directory+json`. | ||
|
||
For `/repositories/https_github.com_TabbyML_tabby.git/resolve/ee/tabby-webserver/`, the response is: | ||
|
||
```json | ||
{ | ||
"entries": [ | ||
"ee/tabby-webserver/src", | ||
"ee/tabby-webserver/ui", | ||
"ee/tabby-webserver/examples", | ||
"ee/tabby-webserver/Cargo.toml", | ||
"ee/tabby-webserver/graphql" | ||
] | ||
} | ||
``` | ||
|
||
- The file query will return file content, the `Content-Type` will be guessed from the file extension. | ||
|
||
For request `/repositories/https_github.com_TabbyML_tabby.git/resolve/package.json`, the content type is `application/json`, and the response is: | ||
|
||
```json | ||
{ | ||
"private": true, | ||
"workspaces": [ | ||
"clients/tabby-agent", | ||
"clients/vscode", | ||
"clients/vim", | ||
"clients/intellij" | ||
], | ||
"engines": { | ||
"node": ">=18" | ||
} | ||
} | ||
``` | ||
|
||
For request `/repositories/https_github.com_TabbyML_tabby.git/resolve/ee/tabby-webserver/src/api.rs`, the content type is `text/x-rust`, and the response is: | ||
|
||
```text | ||
use async_trait::async_trait; | ||
use juniper::{GraphQLEnum, GraphQLObject}; | ||
use serde::{Deserialize, Serialize}; | ||
use tabby_common::api::{ | ||
code::{CodeSearch, CodeSearchError, SearchResponse}, | ||
event::RawEventLogger, | ||
}; | ||
use thiserror::Error; | ||
use tokio_tungstenite::connect_async; | ||
use crate::websocket::WebSocketTransport; | ||
#[derive(GraphQLEnum, Serialize, Deserialize, Clone, Debug)] | ||
pub enum WorkerKind { | ||
Completion, | ||
Chat, | ||
} | ||
......omit...... | ||
``` | ||
|
||
### Meta | ||
|
||
Get dataset entry for each indexed file in the repository | ||
|
||
**URL:** `/repositories/{name}/meta/{path}` | ||
|
||
**Method:** `GET` | ||
|
||
**Request example:** | ||
|
||
```shell | ||
curl --request GET \ | ||
--url http://localhost:9090/repositories/https_github.com_TabbyML_tabby.git/meta/ee/tabby-webserver/src/lib.rs | ||
``` | ||
|
||
**Response example:** | ||
|
||
The `Content-Type` for successful response is always `application/json`. | ||
|
||
```json | ||
{ | ||
"git_url": "https://github.com/TabbyML/tabby.git", | ||
"filepath": "ee/tabby-webserver/src/lib.rs", | ||
"language": "rust", | ||
"max_line_length": 88, | ||
"avg_line_length": 26.340782, | ||
"alphanum_fraction": 0.56416017, | ||
"tags": [ | ||
{ | ||
"range": { | ||
"start": 0, | ||
"end": 12 | ||
}, | ||
"name_range": { | ||
"start": 8, | ||
"end": 11 | ||
}, | ||
"line_range": { | ||
"start": 0, | ||
"end": 12 | ||
}, | ||
"is_definition": true, | ||
"syntax_type_name": "module" | ||
}, | ||
......omit...... | ||
] | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
mod resolve; | ||
|
||
use anyhow::Result; | ||
use axum::{extract::Path, http::StatusCode, response::Response, routing, Json, Router}; | ||
use tabby_common::path::repositories_dir; | ||
use tracing::{instrument, warn}; | ||
|
||
use crate::{ | ||
repositories, | ||
repositories::resolve::{resolve_dir, resolve_file, resolve_meta, Meta, ResolveParams}, | ||
}; | ||
|
||
pub fn routes() -> Router { | ||
Router::new() | ||
.route("/:name/resolve/", routing::get(repositories::resolve)) | ||
.route("/:name/resolve/*path", routing::get(repositories::resolve)) | ||
.route("/:name/meta/", routing::get(repositories::meta)) | ||
.route("/:name/meta/*path", routing::get(repositories::meta)) | ||
} | ||
|
||
#[instrument(skip(repo))] | ||
async fn resolve(Path(repo): Path<ResolveParams>) -> Result<Response, StatusCode> { | ||
let root = repositories_dir().join(repo.name_str()); | ||
let full_path = root.join(repo.path_str()); | ||
let is_dir = tokio::fs::metadata(full_path.clone()) | ||
.await | ||
.map(|m| m.is_dir()) | ||
.unwrap_or(false); | ||
|
||
if is_dir { | ||
return match resolve_dir(root, full_path.clone()).await { | ||
Ok(resp) => Ok(resp), | ||
Err(err) => { | ||
warn!("failed to resolve_dir <{:?}>: {}", full_path, err); | ||
Err(StatusCode::INTERNAL_SERVER_ERROR) | ||
} | ||
}; | ||
} | ||
|
||
match resolve_file(root, &repo).await { | ||
Ok(resp) => Ok(resp), | ||
Err(err) => { | ||
warn!("failed to resolve_file <{:?}>: {}", full_path, err); | ||
Err(StatusCode::INTERNAL_SERVER_ERROR) | ||
} | ||
} | ||
} | ||
|
||
#[instrument(skip(repo))] | ||
async fn meta(Path(repo): Path<ResolveParams>) -> Result<Json<Meta>, StatusCode> { | ||
let key = repo.dataset_key(); | ||
if let Some(resp) = resolve_meta(&key) { | ||
return Ok(Json(resp)); | ||
} | ||
Err(StatusCode::NOT_FOUND) | ||
} |
Oops, something went wrong.