diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5ba389a7..bac5ff47 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,6 +13,23 @@ env: CARGO_TERM_COLOR: always jobs: + build: + runs-on: ubuntu-latest + env: + EARTHLY_TOKEN: ${{ secrets.EARTHLY_TOKEN }} + DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} + DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }} + FORCE_COLOR: 1 + steps: + - uses: earthly/actions-setup@v1 + with: + version: v0.7.23 + - uses: actions/checkout@v2 + - name: Docker Login + run: docker login --username "$DOCKERHUB_USERNAME" --password "$DOCKERHUB_TOKEN" + - name: Run build + run: earthly --org applied-knowledge-systems --sat my-satellite --ci --push +docker_all + build-and-test: name: Build and Test runs-on: ubuntu-latest diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 00000000..df11896d --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,40 @@ +name: "publish" +on: + push: + branches: + - release + +jobs: + publish-tauri: + strategy: + fail-fast: false + matrix: + platform: [macos-latest, ubuntu-latest, windows-latest] + + runs-on: ${{ matrix.platform }} + steps: + - uses: actions/checkout@v2 + - name: setup node + uses: actions/setup-node@v1 + with: + node-version: 16 + - name: install Rust stable + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + - name: install dependencies (ubuntu only) + if: matrix.platform == 'ubuntu-latest' + run: | + sudo apt-get update + sudo apt-get install -y libgtk-3-dev webkit2gtk-4.0 libappindicator3-dev librsvg2-dev patchelf + - name: install app dependencies and build it + run: yarn && yarn build + - uses: tauri-apps/tauri-action@v0 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tagName: app-v__VERSION__ # the action automatically replaces \_\_VERSION\_\_ with the app version + releaseName: "App v__VERSION__" + releaseBody: "See the assets to download this version and install." + releaseDraft: true + prerelease: false diff --git a/.github/workflows/test-on-pr.yml b/.github/workflows/test-on-pr.yml new file mode 100644 index 00000000..399490f7 --- /dev/null +++ b/.github/workflows/test-on-pr.yml @@ -0,0 +1,31 @@ +name: "test-on-pr" +on: [pull_request] + +jobs: + test-tauri: + strategy: + fail-fast: false + matrix: + platform: [macos-latest, ubuntu-latest, windows-latest] + + runs-on: ${{ matrix.platform }} + steps: + - uses: actions/checkout@v2 + - name: setup node + uses: actions/setup-node@v1 + with: + node-version: 16 + - name: install Rust stable + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + - name: install dependencies (ubuntu only) + if: matrix.platform == 'ubuntu-latest' + run: | + sudo apt-get update + sudo apt-get install -y libgtk-3-dev webkit2gtk-4.0 libappindicator3-dev librsvg2-dev patchelf + - name: install app dependencies and build it + run: yarn && yarn build + - uses: tauri-apps/tauri-action@v0 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index 677c48d2..7869f503 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ Cargo.lock *.pdb .vscode/ terraphim-grep/ +artifact diff --git a/Cargo.toml b/Cargo.toml index bcd40b9c..53d3ef40 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,10 @@ name = "terraphim_ai" version = "0.1.0" edition = "2021" -default-run="terraphim-server" +rust-version = "1.75" +license = "Apache-2.0" +default-run="terraphim_server" +repository = "https://github.com/terraphim/terraphim-ai/" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [workspace] @@ -18,10 +21,40 @@ members = [ "terraphim_types" ] +[dependencies] +tokio = { version = "1.35.1", features = ["fs", "macros", "rt-multi-thread", "rt"] } +itertools = "0.12.0" +opendal = { version = "0.41.0", features = ["services-dashmap", "services-redis", "services-sled","rustls","services-redis-rustls"] } +terraphim_config={path="crates/config"} +terraphim_pipeline={path="crates/terraphim_pipeline"} +terraphim_types= {path="terraphim_types"} +terraphim_settings={path="crates/settings"} +persistance = {path="crates/persistance"} +terraphim_middleware={path="crates/middleware"} +terraphim_server = {path="server-axum"} +anyhow = "1.0.44" +# FIXME: port picker used in axum and desktop +portpicker = "0.1" +rustls-pemfile = "2.0.0" +[dev-dependencies] +reqwest = {version = "0.11", features = ["json","rustls-tls"]} +tokio = { version = "1", features = ["full"] } +serde_json = "1.0.108" + + [workspace.dependencies] -tokio = { version = "1.35.1", features = ["fs", "macros", "rt-multi-thread"] } -itertools = "0.11.0" -opendal = { version = "0.41.0", features = ["services-dashmap", "services-redis", "services-sled"] } +tokio = { version = "1.35.1", features = ["fs", "macros", "rt-multi-thread", "rt"] } + +[workspace.package] +name = "terraphim_ai" +homepage = "https://terraphim.ai/" +version = "0.1.0" +edition = "2021" +rust-version = "1.75" +license = "Apache-2.0" +default-run="terraphim_server" +repository = "https://github.com/terraphim/terraphim-ai/" +authors = ["Alex Mikhalev alex@terraphim.ai"] [dependencies.clap] @@ -31,5 +64,15 @@ version = "4" [[bin]] bench = false path = "server-axum/src/main.rs" -name = "terraphim-server" +name = "terraphim_server" + +[workspace.lints.rust] +unsafe_code = "forbid" + +[lints] +workspace = true + +[features] +default=["rustls"] +rustls = ["reqwest/rustls-tls-native-roots"] \ No newline at end of file diff --git a/Earthfile b/Earthfile new file mode 100644 index 00000000..09f2317d --- /dev/null +++ b/Earthfile @@ -0,0 +1,124 @@ +VERSION --try --global-cache 0.7 +PROJECT applied-knowledge-systems/terraphim-project +IMPORT ./desktop AS desktop +IMPORT github.com/earthly/lib/rust AS rust +FROM ubuntu:20.04 + +ARG TARGETARCH +ARG TARGETOS +ARG TARGETPLATFORM +ARG --global tag=$TARGETOS-$TARGETARCH +ARG --global TARGETARCH +IF [ "$TARGETARCH" = amd64 ] + ARG --global ARCH=x86_64 +ELSE + ARG --global ARCH=$TARGETARCH +END + +WORKDIR /code + +pipeline: + BUILD desktop+build + BUILD +fmt + BUILD +lint + BUILD +test + BUILD +build + + +# Creates a `./artifact/bin` folder with all binaries +build-all: + BUILD +build # x86_64-unknown-linux-gnu + BUILD +cross-build --TARGET=x86_64-unknown-linux-musl + BUILD +cross-build --TARGET=armv7-unknown-linux-musleabihf + BUILD +cross-build --TARGET=aarch64-unknown-linux-musl + # Errors + # BUILD +cross-build --TARGET=aarch64-apple-darwin + +docker-all: + BUILD --platform=linux/amd64 +docker-musl --TARGET=x86_64-unknown-linux-musl + BUILD --platform=linux/arm/v7 +docker-musl --TARGET=armv7-unknown-linux-musleabihf + BUILD --platform=linux/arm64/v8 +docker-musl --TARGET=aarch64-unknown-linux-musl + +install: + FROM rust:1.75.0-buster + RUN apt-get update -qq + RUN apt install -y musl-tools musl-dev + RUN update-ca-certificates + RUN rustup component add clippy + RUN rustup component add rustfmt + RUN cargo install cross + DO rust+INIT --keep_fingerprints=true + +source: + FROM +install + COPY --keep-ts Cargo.toml Cargo.lock ./ + COPY --keep-ts --dir server-axum desktop crates terraphim_types ./ + COPY desktop+build/dist /code/server-axum/dist + DO rust+CARGO --args=fetch + +cross-build: + FROM +source + ARG --required TARGET + DO rust+SET_CACHE_MOUNTS_ENV + WITH DOCKER + RUN --mount=$EARTHLY_RUST_CARGO_HOME_CACHE --mount=$EARTHLY_RUST_TARGET_CACHE cross build --target $TARGET --release + END + DO rust+COPY_OUTPUT --output=".*" # Copies all files to ./target + RUN ./target/$TARGET/release/terraphim-server --version + SAVE ARTIFACT ./target/$TARGET/release/terraphim-server AS LOCAL artifact/bin/terraphim_server-$TARGET + +build: + FROM +source + DO rust+CARGO --args="build --offline --release" --output="release/[^/\.]+" + RUN ./target/release/terraphim_server --version + SAVE ARTIFACT ./target/release/terraphim_server AS LOCAL artifact/bin/terraphim_server-$TARGET + +test: + FROM +source + DO rust+CARGO --args="test" + +fmt: + FROM +source + DO rust+CARGO --args="fmt --check" + +lint: + FROM +source + DO rust+CARGO --args="clippy --no-deps --all-features --all-targets" + +docker-musl: + FROM alpine:3.18 + # You can pass multiple tags, space separated + # SAVE IMAGE --push ghcr.io/applied-knowledge-systems/terraphim-fastapiapp:bionic + ARG tags="ghcr.io/applied-knowledge-systems/terraphim-server:latest" + ARG --required TARGET + COPY --chmod=0755 --platform=linux/amd64 (+cross-build/terraphim_server --TARGET=${TARGET}) /terraphim_server + RUN /terraphim_server --version + ENV TERRAPHIM_SERVER_HOSTNAME="127.0.0.1:8000" + ENV TERRAPHIM_SERVER_API_ENDPOINT="http://localhost:8000/api" + EXPOSE 8000 + ENTRYPOINT ["/terraphim_server"] + SAVE IMAGE --push ${tags} + +docker-aarch64: + FROM rust:latest + + RUN apt update && apt upgrade -y + RUN apt install -y g++-aarch64-linux-gnu libc6-dev-arm64-cross + + RUN rustup target add aarch64-unknown-linux-gnu + RUN rustup toolchain install stable-aarch64-unknown-linux-gnu + + WORKDIR /app + + ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc \ + CC_aarch64_unknown_linux_gnu=aarch64-linux-gnu-gcc \ + CXX_aarch64_unknown_linux_gnu=aarch64-linux-gnu-g++ + + CMD ["cargo", "build","--release","--target", "aarch64-unknown-linux-gnu"] + +docker-slim: + FROM debian:buster-slim + COPY +build/terraphim_server terraphim_server + EXPOSE 8000 + ENTRYPOINT ["./terraphim_server"] + SAVE IMAGE aks/terraphim_server:buster \ No newline at end of file diff --git a/crates/terraphim_automata/Cargo.toml b/crates/terraphim_automata/Cargo.toml index 56952ee1..99da138d 100644 --- a/crates/terraphim_automata/Cargo.toml +++ b/crates/terraphim_automata/Cargo.toml @@ -9,7 +9,7 @@ edition = "2021" aho-corasick = "1.0.2" csv = "1.2.2" flate2 = "1.0.26" -reqwest = { version="0.11.18", features=["json"]} +reqwest = { version="0.11.18", features=["json","rustls-tls"]} serde = { version = "1.0.163", features = ["derive"] } thiserror = "1.0.30" serde_json="1" diff --git a/crates/terraphim_automata/data/term_to_id.json b/crates/terraphim_automata/data/term_to_id.json new file mode 100644 index 00000000..948c6b88 --- /dev/null +++ b/crates/terraphim_automata/data/term_to_id.json @@ -0,0 +1,622 @@ +{ + "project management framework tailoring": { + "id": 43, + "nterm": "project tailoring strategy" + }, + "strategy documents": { + "id": 50, + "nterm": "strategy documents" + }, + "project constraints": { + "id": 32, + "nterm": "project constraints" + }, + "external condition": { + "id": 32, + "nterm": "project constraints" + }, + "systems engineering management plan": { + "id": 48, + "nterm": "semp" + }, + "portfolio of projects": { + "id": 41, + "nterm": "project portfolio" + }, + "qualified staff": { + "id": 45, + "nterm": "qualified personnel" + }, + "work breakdown structure": { + "id": 52, + "nterm": "work breakdown structure" + }, + "project planning record": { + "id": 39, + "nterm": "project planning record" + }, + "planning of the project": { + "id": 40, + "nterm": "project planning" + }, + "acquisition need": { + "id": 16, + "nterm": "acquisition need" + }, + "program budget": { + "id": 31, + "nterm": "project budget" + }, + "life cycle models": { + "id": 26, + "nterm": "life cycle models" + }, + "skilled staff": { + "id": 45, + "nterm": "qualified personnel" + }, + "state the project": { + "id": 22, + "nterm": "define the project" + }, + "pm": { + "id": 37, + "nterm": "project management (sfia)" + }, + "activate the project": { + "id": 17, + "nterm": "activate the project" + }, + "lifecycle model": { + "id": 26, + "nterm": "life cycle models" + }, + "project retrospective": { + "id": 36, + "nterm": "project lessons learned" + }, + "documentation structure": { + "id": 23, + "nterm": "documentation tree" + }, + "credit card sales voucher": { + "id": 49, + "nterm": "source documents" + }, + "preventive action": { + "id": 44, + "nterm": "qm corrective actions" + }, + "planning of a project": { + "id": 40, + "nterm": "project planning" + }, + "competent staff": { + "id": 45, + "nterm": "qualified personnel" + }, + "spiral": { + "id": 26, + "nterm": "life cycle models" + }, + "infrastructure management plan": { + "id": 35, + "nterm": "project infrastructure needs" + }, + "project deliverable": { + "id": 39, + "nterm": "project planning record" + }, + "project artifacts": { + "id": 39, + "nterm": "project planning record" + }, + "qa corrective action": { + "id": 44, + "nterm": "qm corrective actions" + }, + "staff resources needs": { + "id": 34, + "nterm": "project human resources needs" + }, + "project guidance": { + "id": 33, + "nterm": "project direction" + }, + "human capital requirements": { + "id": 34, + "nterm": "project human resources needs" + }, + "project portfolio": { + "id": 41, + "nterm": "project portfolio" + }, + "purchase order": { + "id": 49, + "nterm": "source documents" + }, + "quality policy": { + "id": 46, + "nterm": "quality assurance plan" + }, + "rfp": { + "id": 16, + "nterm": "acquisition need" + }, + "strategy development": { + "id": 50, + "nterm": "strategy documents" + }, + "life cycle stages": { + "id": 26, + "nterm": "life cycle models" + }, + "specify the project": { + "id": 22, + "nterm": "define the project" + }, + "strategic roadmap": { + "id": 50, + "nterm": "strategy documents" + }, + "8d": { + "id": 44, + "nterm": "qm corrective actions" + }, + "qa plan": { + "id": 46, + "nterm": "quality assurance plan" + }, + "pipeline of projects": { + "id": 41, + "nterm": "project portfolio" + }, + "documentation outline": { + "id": 23, + "nterm": "documentation tree" + }, + "personnel needs": { + "id": 34, + "nterm": "project human resources needs" + }, + "project plan": { + "id": 42, + "nterm": "project schedule" + }, + "strategic map": { + "id": 50, + "nterm": "strategy documents" + }, + "documentation map": { + "id": 23, + "nterm": "documentation tree" + }, + "@102 - prof. michael levin, prof. irina rish - emergence, intelligence, transhumanism.___": { + "id": 1, + "nterm": "@102 - prof. michael levin, prof. irina rish - emergence, intelligence, transhumanism.___" + }, + "goals and objectives": { + "id": 50, + "nterm": "strategy documents" + }, + "project lessons learned": { + "id": 36, + "nterm": "project lessons learned" + }, + "mission and vision": { + "id": 50, + "nterm": "strategy documents" + }, + "qm corrective actions": { + "id": 44, + "nterm": "qm corrective actions" + }, + "documentation hierarchy": { + "id": 23, + "nterm": "documentation tree" + }, + "capa": { + "id": 44, + "nterm": "qm corrective actions" + }, + "budget of a program": { + "id": 31, + "nterm": "project budget" + }, + "project outline": { + "id": 40, + "nterm": "project planning" + }, + "bottleneck": { + "id": 32, + "nterm": "project constraints" + }, + "pages_logseq_project management (sfia)": { + "id": 9, + "nterm": "pages_logseq_project management (sfia)" + }, + "limitation": { + "id": 32, + "nterm": "project constraints" + }, + "quality control plan": { + "id": 46, + "nterm": "quality assurance plan" + }, + "describe the project": { + "id": 22, + "nterm": "define the project" + }, + "project infrastructure needs": { + "id": 35, + "nterm": "project infrastructure needs" + }, + "project management (sfia)": { + "id": 37, + "nterm": "project management (sfia)" + }, + "project scheduling": { + "id": 40, + "nterm": "project planning" + }, + "2023_02_23": { + "id": 4, + "nterm": "2023_02_23" + }, + "documentation tree": { + "id": 23, + "nterm": "documentation tree" + }, + "project direction": { + "id": 33, + "nterm": "project direction" + }, + "project strategy": { + "id": 40, + "nterm": "project planning" + }, + "pbs": { + "id": 52, + "nterm": "work breakdown structure" + }, + "project review": { + "id": 36, + "nterm": "project lessons learned" + }, + "invoice or bill": { + "id": 49, + "nterm": "source documents" + }, + "planning projects": { + "id": 40, + "nterm": "project planning" + }, + "r&d plan": { + "id": 48, + "nterm": "semp" + }, + "it strategy": { + "id": 50, + "nterm": "strategy documents" + }, + "restriction": { + "id": 32, + "nterm": "project constraints" + }, + "project proposal": { + "id": 40, + "nterm": "project planning" + }, + "supply response": { + "id": 51, + "nterm": "supply response" + }, + "petty cash voucher": { + "id": 49, + "nterm": "source documents" + }, + "project planning": { + "id": 40, + "nterm": "project planning" + }, + "quality assurance plan": { + "id": 46, + "nterm": "quality assurance plan" + }, + "regulation": { + "id": 32, + "nterm": "project constraints" + }, + "lessons learned": { + "id": 36, + "nterm": "project lessons learned" + }, + "project manager": { + "id": 37, + "nterm": "project management (sfia)" + }, + "project enabler": { + "id": 35, + "nterm": "project infrastructure needs" + }, + "organization strategic plan": { + "id": 28, + "nterm": "organization strategic plan" + }, + "project post-mortem": { + "id": 36, + "nterm": "project lessons learned" + }, + "project human resources needs": { + "id": 34, + "nterm": "project human resources needs" + }, + "cheque": { + "id": 49, + "nterm": "source documents" + }, + "engineering plan": { + "id": 48, + "nterm": "semp" + }, + "life cycle framework": { + "id": 26, + "nterm": "life cycle models" + }, + "program portfolio": { + "id": 41, + "nterm": "project portfolio" + }, + "life cycle processes": { + "id": 26, + "nterm": "life cycle models" + }, + "credit note": { + "id": 49, + "nterm": "source documents" + }, + "qualified personnel": { + "id": 45, + "nterm": "qualified personnel" + }, + "competitive bid request": { + "id": 16, + "nterm": "acquisition need" + }, + "human assets requirements": { + "id": 34, + "nterm": "project human resources needs" + }, + "semp": { + "id": 48, + "nterm": "semp" + }, + "set of projects": { + "id": 41, + "nterm": "project portfolio" + }, + "project infrastructure requirements": { + "id": 35, + "nterm": "project infrastructure needs" + }, + "2023-06-27t09_34_56.000z.desktop": { + "id": 12, + "nterm": "2023-06-27t09_34_56.000z.desktop" + }, + "project governance": { + "id": 33, + "nterm": "project direction" + }, + "technical management plan": { + "id": 48, + "nterm": "semp" + }, + "project budget": { + "id": 31, + "nterm": "project budget" + }, + "call for proposals": { + "id": 16, + "nterm": "acquisition need" + }, + "project roadmap": { + "id": 42, + "nterm": "project schedule" + }, + "manpower requirements": { + "id": 34, + "nterm": "project human resources needs" + }, + "quality assurance process": { + "id": 46, + "nterm": "quality assurance plan" + }, + "corporate strategy": { + "id": 50, + "nterm": "strategy documents" + }, + "rfq": { + "id": 16, + "nterm": "acquisition need" + }, + "outline the project": { + "id": 22, + "nterm": "define the project" + }, + "quality plan": { + "id": 46, + "nterm": "quality assurance plan" + }, + "life cycle methodology": { + "id": 26, + "nterm": "life cycle models" + }, + "project blueprint": { + "id": 40, + "nterm": "project planning" + }, + "budget of a project": { + "id": 31, + "nterm": "project budget" + }, + "project timeline": { + "id": 42, + "nterm": "project schedule" + }, + "preventive measure": { + "id": 44, + "nterm": "qm corrective actions" + }, + "response management": { + "id": 51, + "nterm": "supply response" + }, + "project chart": { + "id": 42, + "nterm": "project schedule" + }, + "project evaluation": { + "id": 36, + "nterm": "project lessons learned" + }, + "strategy execution": { + "id": 50, + "nterm": "strategy documents" + }, + "vee": { + "id": 26, + "nterm": "life cycle models" + }, + "swot": { + "id": 50, + "nterm": "strategy documents" + }, + "project pipeline": { + "id": 41, + "nterm": "project portfolio" + }, + "prohibition": { + "id": 32, + "nterm": "project constraints" + }, + "project planner iso15288": { + "id": 38, + "nterm": "project planner iso15288" + }, + "detail the project": { + "id": 22, + "nterm": "define the project" + }, + "project management methodology tailoring": { + "id": 43, + "nterm": "project tailoring strategy" + }, + "program": { + "id": 41, + "nterm": "project portfolio" + }, + "planning of projects": { + "id": 40, + "nterm": "project planning" + }, + "project management": { + "id": 37, + "nterm": "project management (sfia)" + }, + "sales order": { + "id": 49, + "nterm": "source documents" + }, + "ishikawa diagram": { + "id": 44, + "nterm": "qm corrective actions" + }, + "documentation chart": { + "id": 23, + "nterm": "documentation tree" + }, + "supporting documents": { + "id": 49, + "nterm": "source documents" + }, + "project funds": { + "id": 31, + "nterm": "project budget" + }, + "cash memo": { + "id": 49, + "nterm": "source documents" + }, + "documentation archive": { + "id": 23, + "nterm": "documentation tree" + }, + "strategic plan": { + "id": 50, + "nterm": "strategy documents" + }, + "plan project and technical management": { + "id": 29, + "nterm": "plan project and technical management" + }, + "waterfall": { + "id": 26, + "nterm": "life cycle models" + }, + "project design": { + "id": 40, + "nterm": "project planning" + }, + "experienced personnel": { + "id": 45, + "nterm": "qualified personnel" + }, + "project tailoring strategy": { + "id": 43, + "nterm": "project tailoring strategy" + }, + "project management process tailoring": { + "id": 43, + "nterm": "project tailoring strategy" + }, + "project schedule": { + "id": 42, + "nterm": "project schedule" + }, + "define the project": { + "id": 22, + "nterm": "define the project" + }, + "competent personnel": { + "id": 45, + "nterm": "qualified personnel" + }, + "project calendar": { + "id": 42, + "nterm": "project schedule" + }, + "systems engineering plan": { + "id": 48, + "nterm": "semp" + }, + "manager": { + "id": 37, + "nterm": "project management (sfia)" + }, + "program governance": { + "id": 33, + "nterm": "project direction" + }, + "source documents": { + "id": 49, + "nterm": "source documents" + }, + "wbs": { + "id": 52, + "nterm": "work breakdown structure" + }, + "skilled personnel": { + "id": 45, + "nterm": "qualified personnel" + } +} \ No newline at end of file diff --git a/desktop/Earthfile b/desktop/Earthfile new file mode 100644 index 00000000..cfb7aae9 --- /dev/null +++ b/desktop/Earthfile @@ -0,0 +1,16 @@ +VERSION 0.7 +FROM node:21.5.0 + +WORKDIR frontend + +deps: + # COPY package.json tsconfig.json yarn.lock vite.config.ts tsconfig.node.json index.html ./ + COPY . . + COPY --dir src src + COPY --dir public public + RUN yarn + +build: + FROM +deps + RUN yarn run build + SAVE ARTIFACT dist /dist AS LOCAL dist \ No newline at end of file diff --git a/desktop/src-tauri/Cargo.toml b/desktop/src-tauri/Cargo.toml index de41e08b..bcc0bd82 100644 --- a/desktop/src-tauri/Cargo.toml +++ b/desktop/src-tauri/Cargo.toml @@ -20,7 +20,7 @@ terraphim_pipeline= {path="../../crates/terraphim_pipeline"} terraphim_types= {path="../../terraphim_types"} terraphim_settings= {path="../../crates/settings"} terraphim_server= {path = "../../server-axum"} -# terraphim_grep = {path="../../crates/terraphim-grep" } +terraphim_middleware = {path="../../crates/middleware" } serde_json = "1.0" serde = { version = "1.0", features = ["derive"] } tauri = { version = "1.5.2", features = ["api-all", "cli", "system-tray"] } diff --git a/desktop/src-tauri/config.txt b/desktop/src-tauri/config.txt deleted file mode 100644 index 0e53ae4e..00000000 --- a/desktop/src-tauri/config.txt +++ /dev/null @@ -1,9 +0,0 @@ -[source.crates-io] -replace-with = "vendored-sources" - -[source."git+https://github.com/mehcode/config-rs.git"] -git = "https://github.com/mehcode/config-rs.git" -replace-with = "vendored-sources" - -[source.vendored-sources] -directory = "vendor" \ No newline at end of file diff --git a/desktop/src-tauri/src/cmd.rs b/desktop/src-tauri/src/cmd.rs index 219539eb..1bf0252c 100644 --- a/desktop/src-tauri/src/cmd.rs +++ b/desktop/src-tauri/src/cmd.rs @@ -7,8 +7,13 @@ use serde::{Serialize,Deserialize}; use tauri::command; use tauri::State; use std::error::Error; +use std::ops::Deref; use anyhow::{Context, Result}; -use terraphim_grep::scan_path; +use terraphim_pipeline::IndexedDocument; +use terraphim_types::{merge_and_serialize, Article, ConfigState, SearchQuery}; + +use terraphim_middleware::search_haystacks; + #[derive(Debug, Deserialize)] #[allow(dead_code)] pub struct RequestBody { @@ -45,29 +50,19 @@ pub async fn my_custom_command(value: &str) -> Result { #[command] -pub async fn search(config_state: State<'_, ConfigState>,needle: String, skip:Option,limit:Option,role: Option) -> Result { - let role=role.as_deref().unwrap_or("Engineer"); - let current_config = config_state.config.lock().await; - let config_role= current_config.roles.get(role).unwrap(); - println!("{} {}", needle, role); - for each_haystack in &config_role.haystacks { - println!("{:?}", each_haystack); - match each_haystack.service.as_str() { - "terraphim-grep" => { - println!("Terraphim Grep called with {needle} {:?}", each_haystack.haystack); - scan_path(&needle, each_haystack.haystack.clone(),None); - } - "rustb" => { - println!("{:?}", each_haystack.haystack); - } - _ => { - println!("{:?}", each_haystack.haystack); - } - } -} - println!("{:?}", config_role.haystacks.len()); +pub async fn search(config_state: State<'_, ConfigState>,search_query:SearchQuery) -> Result, TerraphimTauriError> { + println!("Search called with {:?}", search_query); + let current_config_state= config_state.inner().clone(); + let articles_cached = search_haystacks(current_config_state, search_query.clone()) + .await + .context("Failed to search articles").unwrap(); +let docs: Vec = config_state + .search_articles(search_query) + .await + .expect("Failed to search articles"); + let articles = merge_and_serialize(articles_cached, docs).unwrap(); - Ok("search response".into()) + Ok(articles) } #[command] @@ -89,7 +84,6 @@ pub fn get_port(port: tauri::State) -> Result { use terraphim_server::axum_server; use std::net::SocketAddr; -use terraphim_types::ConfigState; use terraphim_settings::Settings; #[tauri::command] diff --git a/desktop/src-tauri/src/main.rs b/desktop/src-tauri/src/main.rs index 6d3ff239..9e530bc5 100644 --- a/desktop/src-tauri/src/main.rs +++ b/desktop/src-tauri/src/main.rs @@ -81,6 +81,7 @@ async fn main() -> Result<(), Box> { .manage(config_state.clone()) .invoke_handler(tauri::generate_handler![ cmd::my_custom_command, + cmd::search, cmd::get_config, cmd::log_operation, cmd::perform_request, diff --git a/desktop/src/lib/Search/Search.svelte b/desktop/src/lib/Search/Search.svelte index 0e5ae42e..9a3edbbe 100644 --- a/desktop/src/lib/Search/Search.svelte +++ b/desktop/src/lib/Search/Search.svelte @@ -14,12 +14,17 @@ if ($is_tauri) { console.log("Tauri config"); console.log($input); - invoke('search', { + invoke('search', { searchQuery: { search_term: $input, skip: 0, limit: 10, role: $role, - }); + }}) + .then(data => { + console.log(data); + result = data; + }) + .catch(e => console.error(e)); } else { console.log($input); console.log("Role config"); diff --git a/server-axum/.gitignore b/server-axum/.gitignore new file mode 100644 index 00000000..a261f291 --- /dev/null +++ b/server-axum/.gitignore @@ -0,0 +1 @@ +dist/* diff --git a/server-axum/Cargo.toml b/server-axum/Cargo.toml index 50cf370f..94ef9e6c 100644 --- a/server-axum/Cargo.toml +++ b/server-axum/Cargo.toml @@ -1,9 +1,17 @@ [package] name = "terraphim_server" -version = "0.1.0" -edition = "2021" +authors.workspace = true +edition.workspace = true +homepage.workspace = true +license.workspace = true +repository.workspace = true +rust-version.workspace = true +version.workspace = true + +[[bin]] +name = "terraphim_server" +path = "src/main.rs" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] terraphim_config={path="../crates/config"} @@ -12,8 +20,10 @@ terraphim_types= {path="../terraphim_types"} terraphim_settings={path="../crates/settings"} persistance = {path="../crates/persistance"} terraphim_middleware={path="../crates/middleware"} +clap = { version = "4.4.18", features = ["derive"] } -axum = {version ="0.6.20", features = ["macros"]} +axum = {version ="0.7.4", features = ["macros"]} +axum-extra = {version ="0.6.0"} tokio = { version = "1.22.0", features = ["full"] } serde = { version = "1.0.149", features = ["derive"] } utoipa = { features = ["axum_extras"], version = "4.1.0" } @@ -26,9 +36,15 @@ log = "0.4.14" anyhow = "1.0.44" portpicker = "0.1" tokio-stream = { version = "0.1.14", features = ["sync"] } -tower-http = { version = "0.2", features = ["cors"] } +tower-http = { version = "0.5.1", features = ["cors","fs", "trace"] } +tower = { version = "0.4", features = ["util"] } +# axum-embed = "0.1.0" +rust-embed = { version = "8.2.0", features = ["axum", "axum-ex","mime-guess"] } +mime_guess = "2.0.4" [dev-dependencies] -reqwest = {version = "0.11", features = ["json"]} +reqwest = {version = "0.11", features = ["json","rustls-tls"]} tokio = { version = "1", features = ["full"] } -serde_json = "1.0.108" \ No newline at end of file +serde_json = "1.0.108" + + diff --git a/server-axum/Earthfile b/server-axum/Earthfile new file mode 100644 index 00000000..a9683869 --- /dev/null +++ b/server-axum/Earthfile @@ -0,0 +1,65 @@ +VERSION --try --global-cache 0.7 +PROJECT applied-knowledge-systems/terraphim-project +IMPORT ../desktop AS desktop +IMPORT github.com/earthly/lib/rust AS rust +FROM ubuntu:20.04 + +ARG TARGETARCH +ARG TARGETOS +ARG TARGETPLATFORM +ARG --global tag=$TARGETOS-$TARGETARCH +ARG --global TARGETARCH +IF [ "$TARGETARCH" = amd64 ] + ARG --global ARCH=x86_64 +ELSE + ARG --global ARCH=$TARGETARCH +END + +WORKDIR /code + +pipeline: + BUILD desktop+build + BUILD +fmt + BUILD +lint + BUILD +test + BUILD +build + + +install: + FROM rust:1.75.0-buster + RUN apt-get update -qq + RUN apt install -y musl-tools musl-dev + RUN update-ca-certificates + RUN rustup component add clippy + RUN rustup component add rustfmt + RUN cargo install cross + DO rust+INIT --keep_fingerprints=true + +source: + FROM +install + COPY --keep-ts --dir . . + COPY desktop+build/dist /code/server-axum/dist + DO rust+CARGO --args=fetch --keep-fingerprints=true + SAVE ARTIFACT dist as LOCAL /dist + +build: + FROM +source + DO rust+CARGO --args="build --offline --release" --output="release/[^/\.]+" + RUN ./target/release/terraphim_server --version + SAVE ARTIFACT ./target/release/terraphim_server AS LOCAL artifact/bin/terraphim_server-$TARGET + +test: + FROM +source + DO rust+CARGO --args="test" + +fmt: + FROM +source + DO rust+CARGO --args="fmt --check" + +lint: + FROM +source + DO rust+CARGO --args="clippy --no-deps --all-features --all-targets" + +save-fe-local: + COPY desktop+build/dist ./dist + SAVE ARTIFACT ./dist AS LOCAL ./dist \ No newline at end of file diff --git a/server-axum/README.md b/server-axum/README.md index 1fc01953..c29cc8d0 100644 --- a/server-axum/README.md +++ b/server-axum/README.md @@ -3,4 +3,10 @@ Axum Server for Terraphim AI This is the Axum server for Terraphim AI. It is a simple server that serves /config and /search API endpoints. Note: axum have it's own default/settings.toml file to configure the server depending on the device capabilities. -it will copy default/settings.toml to ~/.config/terraphim/settings.toml if it doesn't exist on MacOS and Linux. \ No newline at end of file +it will copy default/settings.toml to ~/.config/terraphim/settings.toml if it doesn't exist on MacOS and Linux. + +To build locally, run: +``` +earthly +save-fe-local +carog build +``` diff --git a/server-axum/default/settings.toml b/server-axum/default/settings.toml index 0553ba69..47b2a4b8 100644 --- a/server-axum/default/settings.toml +++ b/server-axum/default/settings.toml @@ -1,5 +1,5 @@ -server_hostname = "127.0.0.1:8000" -api_endpoint="http://localhost:8000/api" +server_hostname = "${TERRAPHIM_SERVER_HOSTNAME}-127.0.0.1:8000" +api_endpoint="${TERRAPHIM_SERVER_API_ENDPOINT}-http://localhost:8000/api" [profiles.s3] type = "s3" diff --git a/server-axum/src/api.rs b/server-axum/src/api.rs index 88be00bb..f53a8733 100644 --- a/server-axum/src/api.rs +++ b/server-axum/src/api.rs @@ -46,7 +46,7 @@ pub(crate) async fn create_article( (StatusCode::CREATED, response) } -pub(crate) async fn list_articles( +pub(crate) async fn _list_articles( State(rolegraph): State>>, ) -> impl IntoResponse { let rolegraph = rolegraph.lock().await.clone(); @@ -58,7 +58,7 @@ pub(crate) async fn list_articles( /// Search All TerraphimGraphs defined in a config by query params. #[axum::debug_handler] pub(crate) async fn search_articles( - Extension(tx): Extension, + Extension(_tx): Extension, State(config_state): State, search_query: Query, ) -> Result>> { @@ -79,7 +79,7 @@ pub(crate) async fn search_articles( /// Search All TerraphimGraphs defined in a config by post params. /// FIXME: add title, url and body to search output pub(crate) async fn search_articles_post( - Extension(tx): Extension, + Extension(_tx): Extension, State(config_state): State, search_query: Json, ) -> Result>> { diff --git a/server-axum/src/lib.rs b/server-axum/src/lib.rs index d2e56303..e17a93cf 100644 --- a/server-axum/src/lib.rs +++ b/server-axum/src/lib.rs @@ -1,10 +1,12 @@ use axum::{ - http::Method, + http::{header,Method,StatusCode,Uri}, routing::{get, post}, Extension, Router, + response::{Html, IntoResponse, Response}, }; -use std::net::SocketAddr; +use std::net::SocketAddr; +use tower::ServiceExt; mod api; use api::{create_article, health_axum, search_articles, search_articles_post}; use portpicker; @@ -12,15 +14,30 @@ use terraphim_pipeline::IndexedDocument; use terraphim_types as types; use tokio::sync::broadcast::channel; use tower_http::cors::{Any, CorsLayer}; +use tower_http::{ + services::{ServeDir, ServeFile}, + trace::TraceLayer, +}; mod error; pub use error::Result; +use rust_embed::RustEmbed; +// use axum_embed::ServeEmbed; +static INDEX_HTML: &str = "index.html"; + +#[derive(RustEmbed, Clone)] +#[folder = "dist/"] +struct Assets; + + pub async fn axum_server(server_hostname: SocketAddr, config_state: types::ConfigState) { + + // let assets = axum_embed::ServeEmbed::::with_parameters(Some("index.html".to_owned()),axum_embed::FallbackBehavior::Ok, Some("index.html".to_owned())); let (tx, _rx) = channel::(10); + let app = Router::new() - .route("/", get(health_axum)) .route("/health", get(health_axum)) // .route("/articles", get(list_articles)) .route("/article", post(create_article)) @@ -31,6 +48,7 @@ pub async fn axum_server(server_hostname: SocketAddr, config_state: types::Confi .route("/config/", get(api::show_config)) .route("/config", post(api::update_config)) .route("/config/", post(api::update_config)) + .fallback(static_handler) .with_state(config_state) .layer(Extension(tx)) .layer( @@ -47,14 +65,52 @@ pub async fn axum_server(server_hostname: SocketAddr, config_state: types::Confi ); println!("listening on {server_hostname}"); - axum::Server::bind(&server_hostname) - .serve(app.into_make_service()) - .await - .unwrap_or_else(|_| { - // FIXME: this unwrap is never reached - // the desired behavior is to pick a new port and try again - let port = portpicker::pick_unused_port().expect("failed to find unused port"); - let add = SocketAddr::from(([127, 0, 0, 1], port)); - println!("listening on {add} with {port}"); - }); + let listener = tokio::net::TcpListener::bind(server_hostname).await.unwrap(); + axum::serve(listener, app).await.unwrap(); + + // axum::Server::bind(&server_hostname) + // .serve(app.into_make_service()) + // .await + // .unwrap_or_else(|_| { + // // FIXME: this unwrap is never reached + // // the desired behavior is to pick a new port and try again + // let port = portpicker::pick_unused_port().expect("failed to find unused port"); + // let add = SocketAddr::from(([127, 0, 0, 1], port)); + // println!("listening on {add} with {port}"); + // }); } + + +async fn static_handler(uri: Uri) -> impl IntoResponse { + let path = uri.path().trim_start_matches('/'); + + if path.is_empty() || path == INDEX_HTML { + return index_html().await; + } + + match Assets::get(path) { + Some(content) => { + let mime = mime_guess::from_path(path).first_or_octet_stream(); + + ([(header::CONTENT_TYPE, mime.as_ref())], content.data).into_response() + } + None => { + if path.contains('.') { + return not_found().await; + } + + index_html().await + } + } + } + + async fn index_html() -> Response { + match Assets::get(INDEX_HTML) { + Some(content) => Html(content.data).into_response(), + None => not_found().await, + } + } + + async fn not_found() -> Response { + (StatusCode::NOT_FOUND, "404").into_response() + } diff --git a/server-axum/src/main.rs b/server-axum/src/main.rs index 2ec0ca12..51cac779 100644 --- a/server-axum/src/main.rs +++ b/server-axum/src/main.rs @@ -13,7 +13,7 @@ )] #![deny(anonymous_parameters, macro_use_extern_crate, pointer_structural_match)] // #![deny(missing_docs)] - +use clap::Parser; use anyhow::Context; use std::net::SocketAddr; use std::sync::Arc; @@ -27,8 +27,23 @@ use portpicker; /// TODO: Can't get Open API docs to work with axum consitently, given up for now. use terraphim_pipeline::RoleGraph; +#[derive(Parser, Debug)] +#[command(author, version, about, long_about = None)] +struct Args { + /// String to search for + #[arg(short, long)] + search_term: Option, + + /// Role to use for search + #[arg(short, long)] + role: Option, +} + #[tokio::main] async fn main() -> Result<()> { + + let args = Args::parse(); + println!("args: {:?}", args); let server_settings = Settings::load_from_env_and_file(None) .context("Failed to load settings from environment")?; println!( @@ -43,6 +58,7 @@ async fn main() -> Result<()> { let port = portpicker::pick_unused_port().expect("failed to find unused port"); SocketAddr::from(([127, 0, 0, 1], port)) }); + let mut config_state = types::ConfigState::new().await?; // Add one more for testing local KG diff --git a/src/main.rs b/src/main.rs deleted file mode 100644 index 5bf256ea..00000000 --- a/src/main.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - println!("Hello world"); -} diff --git a/terraphim_types/src/lib.rs b/terraphim_types/src/lib.rs index bd29d818..44bf5e96 100644 --- a/terraphim_types/src/lib.rs +++ b/terraphim_types/src/lib.rs @@ -114,8 +114,8 @@ pub struct ConfigState { impl ConfigState { pub async fn new() -> Result { let mut config = TerraphimConfig::new(); - // Try to load the existing state - let config = config.load("configstate").await?; + // Try to load the existing state of the config + let config = config.load("configstate").await.unwrap_or_default(); println!("Config loaded"); let mut config_state = ConfigState { config: Arc::new(Mutex::new(config.clone())),