configure grpc
This commit is contained in:
30
.dockerignore
Normal file
30
.dockerignore
Normal file
@@ -0,0 +1,30 @@
|
||||
**/.classpath
|
||||
**/.dockerignore
|
||||
**/.env
|
||||
**/.git
|
||||
**/.gitignore
|
||||
**/.project
|
||||
**/.settings
|
||||
**/.toolstarget
|
||||
**/.vs
|
||||
**/.vscode
|
||||
**/*.*proj.user
|
||||
**/*.dbmdl
|
||||
**/*.jfm
|
||||
**/azds.yaml
|
||||
**/bin
|
||||
**/charts
|
||||
**/docker-compose*
|
||||
**/Dockerfile*
|
||||
**/node_modules
|
||||
**/npm-debug.log
|
||||
**/obj
|
||||
**/secrets.dev.yaml
|
||||
**/values.dev.yaml
|
||||
LICENSE
|
||||
README.md
|
||||
!**/.gitignore
|
||||
!.git/HEAD
|
||||
!.git/config
|
||||
!.git/packed-refs
|
||||
!.git/refs/heads/**
|
||||
@@ -1,21 +0,0 @@
|
||||
syntax = "proto3";
|
||||
|
||||
option csharp_namespace = "AZKi_Server";
|
||||
|
||||
package greet;
|
||||
|
||||
// The greeting service definition.
|
||||
service Greeter {
|
||||
// Sends a greeting
|
||||
rpc SayHello (HelloRequest) returns (HelloReply);
|
||||
}
|
||||
|
||||
// The request message containing the user's name.
|
||||
message HelloRequest {
|
||||
string name = 1;
|
||||
}
|
||||
|
||||
// The response message containing the greetings.
|
||||
message HelloReply {
|
||||
string message = 1;
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
using AZKiServer;
|
||||
using Grpc.Core;
|
||||
|
||||
namespace AZKiServer.Services
|
||||
{
|
||||
public class GreeterService : Greeter.GreeterBase
|
||||
{
|
||||
private readonly ILogger<GreeterService> _logger;
|
||||
public GreeterService(ILogger<GreeterService> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
|
||||
{
|
||||
return Task.FromResult(new HelloReply
|
||||
{
|
||||
Message = "Hello " + request.Name
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
1
AZKiServer/.dockerignore
Normal file
1
AZKiServer/.dockerignore
Normal file
@@ -0,0 +1 @@
|
||||
wwwroot
|
||||
@@ -8,7 +8,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Protobuf Include="Protos\greet.proto" GrpcServices="Server" />
|
||||
<Protobuf Include="Protos\*.proto" GrpcServices="Server" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -12,10 +12,11 @@ public partial class MediaEntry
|
||||
{
|
||||
[BsonId]
|
||||
public ObjectId Id { get; set; }
|
||||
public int Version { get; set; }
|
||||
public MediaType Type { get; set; }
|
||||
public required string Filepath { get; set; }
|
||||
public DateTime Date { get; set; }
|
||||
public byte CameraId { get; set; }
|
||||
public int CameraId { get; set; }
|
||||
|
||||
public static Maybe<MediaEntry> Parse(string relativePath)
|
||||
{
|
||||
@@ -34,7 +35,7 @@ public partial class MediaEntry
|
||||
|
||||
return new MediaEntry
|
||||
{
|
||||
CameraId = byte.Parse(cam.Value),
|
||||
CameraId = int.Parse(cam.Value),
|
||||
Filepath = relativePath,
|
||||
Date = ParseDate(date.Value),
|
||||
Type = ext.Value switch
|
||||
12
AZKiServer/Protos/azki.proto
Normal file
12
AZKiServer/Protos/azki.proto
Normal file
@@ -0,0 +1,12 @@
|
||||
syntax = "proto3";
|
||||
|
||||
option csharp_namespace = "AZKiServer.RPC";
|
||||
package azki;
|
||||
|
||||
import "google/protobuf/empty.proto";
|
||||
import "Protos/types.proto";
|
||||
|
||||
|
||||
service AZKi{
|
||||
rpc GetMediaEntriesInRange(MediaRangeRequest) returns (MediaList);
|
||||
}
|
||||
33
AZKiServer/Protos/types.proto
Normal file
33
AZKiServer/Protos/types.proto
Normal file
@@ -0,0 +1,33 @@
|
||||
syntax = "proto3";
|
||||
|
||||
option csharp_namespace = "AZKiServer.RPC";
|
||||
package azki;
|
||||
|
||||
import "google/protobuf/timestamp.proto";
|
||||
import "google/protobuf/empty.proto";
|
||||
|
||||
enum MediaType {
|
||||
None = 0;
|
||||
Image = 1;
|
||||
Video = 2;
|
||||
All = 3;
|
||||
}
|
||||
|
||||
message MediaList {
|
||||
repeated MediaEntry entries = 1;
|
||||
}
|
||||
|
||||
message MediaRangeRequest{
|
||||
MediaType type = 1;
|
||||
google.protobuf.Timestamp from = 2;
|
||||
google.protobuf.Timestamp to = 3;
|
||||
}
|
||||
|
||||
message MediaEntry {
|
||||
int32 version = 1;
|
||||
string id = 2;
|
||||
MediaType type = 3;
|
||||
string filePath = 4;
|
||||
int32 cameraId = 5;
|
||||
google.protobuf.Timestamp date = 6;
|
||||
}
|
||||
41
AZKiServer/RPC/ConversionExtensions.cs
Normal file
41
AZKiServer/RPC/ConversionExtensions.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
namespace AZKiServer.RPC;
|
||||
|
||||
public static class ConversionExtensions
|
||||
{
|
||||
public static Models.MediaType FromRpc(this MediaType type)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
MediaType.None => Models.MediaType.None,
|
||||
MediaType.Image => Models.MediaType.Image,
|
||||
MediaType.Video => Models.MediaType.Video,
|
||||
MediaType.All => Models.MediaType.All,
|
||||
_ => throw new NotSupportedException()
|
||||
};
|
||||
}
|
||||
|
||||
public static MediaType ToRpc(this Models.MediaType type)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
Models.MediaType.None => MediaType.None,
|
||||
Models.MediaType.Image => MediaType.Image,
|
||||
Models.MediaType.Video => MediaType.Video,
|
||||
Models.MediaType.All => MediaType.All,
|
||||
_ => throw new NotSupportedException()
|
||||
};
|
||||
}
|
||||
|
||||
public static MediaEntry ToRpc(this Models.MediaEntry entry)
|
||||
{
|
||||
return new MediaEntry
|
||||
{
|
||||
Version = entry.Version,
|
||||
CameraId = entry.CameraId,
|
||||
Date = Google.Protobuf.WellKnownTypes.Timestamp.FromDateTime(entry.Date),
|
||||
FilePath = entry.Filepath,
|
||||
Id = entry.Id.ToString(),
|
||||
Type = entry.Type.ToRpc()
|
||||
};
|
||||
}
|
||||
}
|
||||
20
AZKiServer/Services/AZKiRpcService.cs
Normal file
20
AZKiServer/Services/AZKiRpcService.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using AZKiServer.Models;
|
||||
using AZKiServer.RPC;
|
||||
|
||||
using Google.Protobuf;
|
||||
|
||||
using Grpc.Core;
|
||||
|
||||
namespace AZKiServer.Services;
|
||||
public class AZKiRpcService(MediaService mediaService) : RPC.AZKi.AZKiBase
|
||||
{
|
||||
public override async Task<MediaList> GetMediaEntriesInRange(MediaRangeRequest request, ServerCallContext context)
|
||||
{
|
||||
var from = request.From.ToDateTime();
|
||||
var to = request.To.ToDateTime();
|
||||
var items = await mediaService.GetEntriesInRangeAsync(request.Type.FromRpc(), from, to);
|
||||
var result = new MediaList();
|
||||
result.Entries.AddRange(items.Select(e => e.ToRpc()));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
65
Dockerfile
Normal file
65
Dockerfile
Normal file
@@ -0,0 +1,65 @@
|
||||
# Client Side build - prep deps
|
||||
FROM rust:1-trixie AS chef
|
||||
RUN rustup target add wasm32-unknown-unknown
|
||||
RUN cargo install cargo-chef
|
||||
WORKDIR /app
|
||||
|
||||
FROM chef AS planner
|
||||
COPY . .
|
||||
WORKDIR /app/client
|
||||
RUN cargo chef prepare --recipe-path recipe.json
|
||||
|
||||
FROM chef AS client-builder
|
||||
WORKDIR /app/client
|
||||
COPY --from=planner /app/client/recipe.json recipe.json
|
||||
RUN cargo chef cook --release --recipe-path recipe.json
|
||||
COPY /client /app/client
|
||||
COPY /AZKiServer/Protos /app/AZKiServer/Protos
|
||||
|
||||
# Install Protobuf
|
||||
RUN apt update
|
||||
RUN apt install -y protobuf-compiler libprotobuf-dev ffmpeg
|
||||
|
||||
# Install `dx`
|
||||
RUN curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash
|
||||
RUN cargo binstall dioxus-cli --root /.cargo -y --force
|
||||
ENV PATH="/.cargo/bin:$PATH"
|
||||
ARG VERSION
|
||||
ENV APP_VERSION=$VERSION
|
||||
# Create the final bundle folder. Bundle always executes in release mode with optimizations enabled
|
||||
RUN dx bundle --release --platform web
|
||||
|
||||
# Server Build
|
||||
# This stage is used when running from VS in fast mode (Default for Debug configuration)
|
||||
FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base
|
||||
RUN apt-get update && apt-get install -y ffmpeg #libvips libvips-tools
|
||||
USER $APP_UID
|
||||
WORKDIR /app
|
||||
EXPOSE 8080
|
||||
EXPOSE 8081
|
||||
|
||||
# This stage is used to build the service project
|
||||
FROM mcr.microsoft.com/dotnet/sdk:9.0-noble AS build
|
||||
ARG BUILD_CONFIGURATION=Release
|
||||
WORKDIR /src
|
||||
COPY ["AZKiServer/AZKi Server.csproj", "AZKiServer/"]
|
||||
RUN dotnet restore "./AZKiServer/AZKi Server.csproj"
|
||||
COPY . .
|
||||
# Copy Built bundle from client builder
|
||||
COPY --from=client-builder /app/client/target/dx/azki-client/release/web/public /src/AZKiServer/wwwroot
|
||||
WORKDIR "/src/AZKiServer"
|
||||
# RUN dotnet build "./AZKiServer.csproj" -c $BUILD_CONFIGURATION #-o /app/build
|
||||
|
||||
# This stage is used to publish the service project to be copied to the final stage
|
||||
FROM build AS publish
|
||||
ARG BUILD_CONFIGURATION=Release
|
||||
RUN dotnet publish "./AZKi Server.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
|
||||
|
||||
# This stage is used in production or when running from VS in regular mode (Default when not using the Debug configuration)
|
||||
FROM base AS final
|
||||
WORKDIR /app
|
||||
COPY --from=publish /app/publish .
|
||||
ARG VERSION
|
||||
|
||||
ENV APP_VERSION=$VERSION
|
||||
ENTRYPOINT ["dotnet", "AZKiServer.dll"]
|
||||
6
client/.dockerignore
Normal file
6
client/.dockerignore
Normal file
@@ -0,0 +1,6 @@
|
||||
**/target
|
||||
**/dist
|
||||
LICENSES
|
||||
LICENSE
|
||||
temp
|
||||
README.md
|
||||
619
client/Cargo.lock
generated
619
client/Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "azki"
|
||||
name = "azki-client"
|
||||
version = "0.1.0"
|
||||
authors = ["Amatsugu <khamraj@kaisei.app>"]
|
||||
edition = "2021"
|
||||
@@ -7,19 +7,21 @@ edition = "2021"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
dioxus = { version = "0.7.1", features = ["router"] }
|
||||
dioxus = { version = "0.7.3", features = ["router"] }
|
||||
serde = "1.0.219"
|
||||
serde_repr = "0.1.20"
|
||||
tonic = { version = "*", default-features = false, features = [
|
||||
tonic = { version = "0.14.2", default-features = false, features = [
|
||||
"codegen",
|
||||
"prost",
|
||||
] }
|
||||
prost = "0.13"
|
||||
tonic-web-wasm-client = "0.7"
|
||||
prost = "0.14"
|
||||
prost-types = "0.14"
|
||||
tonic-web-wasm-client = "0.8"
|
||||
web-sys = { version = "0.3.77", features = ["Storage", "Window"] }
|
||||
tokio = "1.49.0"
|
||||
tonic-prost = "0.14.2"
|
||||
|
||||
[build-dependencies]
|
||||
tonic-build = { version = "*", default-features = false, features = ["prost"] }
|
||||
tonic-prost-build = { version = "0.14.2"}
|
||||
dotenv = "0.15.0"
|
||||
|
||||
[features]
|
||||
|
||||
@@ -4,15 +4,14 @@ use std::fs::File;
|
||||
use std::io::Write;
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
// tonic_build::configure()
|
||||
// .build_server(false)
|
||||
// .build_client(true)
|
||||
// .compile_protos(
|
||||
// &[
|
||||
// "",
|
||||
// ],
|
||||
// &[""],
|
||||
// )?;
|
||||
tonic_prost_build::configure()
|
||||
.build_server(false)
|
||||
.build_client(true)
|
||||
.build_transport(false)
|
||||
.compile_protos(
|
||||
&["../AZKiServer/Protos/azki.proto", "../AZKiServer/Protos/types.proto"],
|
||||
&["../AZKiServer"],
|
||||
)?;
|
||||
forward_env();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -4,8 +4,14 @@ mod app;
|
||||
mod components;
|
||||
mod env;
|
||||
mod route;
|
||||
mod rpc;
|
||||
mod views;
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
pub const RPC_HOST: &'static str = "http://localhost:8081";
|
||||
#[cfg(not(debug_assertions))]
|
||||
pub const RPC_HOST: &'static str = "https://grpc.aoba.app:8443";
|
||||
|
||||
fn main() {
|
||||
dioxus::launch(App);
|
||||
}
|
||||
|
||||
49
client/src/rpc.rs
Normal file
49
client/src/rpc.rs
Normal file
@@ -0,0 +1,49 @@
|
||||
use std::sync::RwLock;
|
||||
|
||||
use tonic::service::{interceptor::InterceptedService, Interceptor};
|
||||
use tonic_web_wasm_client::Client;
|
||||
|
||||
use crate::{rpc::azki::az_ki_client::AzKiClient, RPC_HOST};
|
||||
|
||||
pub mod azki {
|
||||
tonic::include_proto!("azki");
|
||||
}
|
||||
|
||||
static RPC_CLIENT: RpcConnection = RpcConnection {
|
||||
azki: RwLock::new(None),
|
||||
jwt: RwLock::new(None),
|
||||
};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct RpcConnection {
|
||||
azki: RwLock<Option<AzKiClient<InterceptedService<Client, AuthInterceptor>>>>,
|
||||
jwt: RwLock<Option<String>>,
|
||||
}
|
||||
|
||||
impl RpcConnection {
|
||||
pub fn get_client(&self) -> AzKiClient<InterceptedService<Client, AuthInterceptor>> {
|
||||
self.ensure_client();
|
||||
return self.azki.read().unwrap().clone().unwrap();
|
||||
}
|
||||
|
||||
fn ensure_client(&self) {
|
||||
if self.azki.read().unwrap().is_none() {
|
||||
let wasm_client = Client::new(RPC_HOST.into());
|
||||
let aoba_client = AzKiClient::with_interceptor(wasm_client.clone(), AuthInterceptor);
|
||||
*self.azki.write().unwrap() = Some(aoba_client);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct AuthInterceptor;
|
||||
impl Interceptor for AuthInterceptor {
|
||||
fn call(&mut self, mut request: tonic::Request<()>) -> Result<tonic::Request<()>, tonic::Status> {
|
||||
if let Some(jwt) = RPC_CLIENT.jwt.read().unwrap().clone() {
|
||||
request
|
||||
.metadata_mut()
|
||||
.insert("authorization", format!("Bearer {jwt}").parse().unwrap());
|
||||
}
|
||||
return Ok(request);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user