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>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Protobuf Include="Protos\greet.proto" GrpcServices="Server" />
|
<Protobuf Include="Protos\*.proto" GrpcServices="Server" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -12,10 +12,11 @@ public partial class MediaEntry
|
|||||||
{
|
{
|
||||||
[BsonId]
|
[BsonId]
|
||||||
public ObjectId Id { get; set; }
|
public ObjectId Id { get; set; }
|
||||||
|
public int Version { get; set; }
|
||||||
public MediaType Type { get; set; }
|
public MediaType Type { get; set; }
|
||||||
public required string Filepath { get; set; }
|
public required string Filepath { get; set; }
|
||||||
public DateTime Date { get; set; }
|
public DateTime Date { get; set; }
|
||||||
public byte CameraId { get; set; }
|
public int CameraId { get; set; }
|
||||||
|
|
||||||
public static Maybe<MediaEntry> Parse(string relativePath)
|
public static Maybe<MediaEntry> Parse(string relativePath)
|
||||||
{
|
{
|
||||||
@@ -34,7 +35,7 @@ public partial class MediaEntry
|
|||||||
|
|
||||||
return new MediaEntry
|
return new MediaEntry
|
||||||
{
|
{
|
||||||
CameraId = byte.Parse(cam.Value),
|
CameraId = int.Parse(cam.Value),
|
||||||
Filepath = relativePath,
|
Filepath = relativePath,
|
||||||
Date = ParseDate(date.Value),
|
Date = ParseDate(date.Value),
|
||||||
Type = ext.Value switch
|
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"]
|
||||||
2
azki.sln
2
azki.sln
@@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00
|
|||||||
# Visual Studio Version 17
|
# Visual Studio Version 17
|
||||||
VisualStudioVersion = 17.14.36908.2 d17.14
|
VisualStudioVersion = 17.14.36908.2 d17.14
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AZKi Server", "AZKi Server\AZKi Server.csproj", "{15810AAC-9BCB-42AD-90B3-F1AA8E134F82}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AZKi Server", "AZKiServer\AZKi Server.csproj", "{15810AAC-9BCB-42AD-90B3-F1AA8E134F82}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
|||||||
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]
|
[package]
|
||||||
name = "azki"
|
name = "azki-client"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
authors = ["Amatsugu <khamraj@kaisei.app>"]
|
authors = ["Amatsugu <khamraj@kaisei.app>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
@@ -7,19 +7,21 @@ edition = "2021"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
dioxus = { version = "0.7.1", features = ["router"] }
|
dioxus = { version = "0.7.3", features = ["router"] }
|
||||||
serde = "1.0.219"
|
serde = "1.0.219"
|
||||||
serde_repr = "0.1.20"
|
serde_repr = "0.1.20"
|
||||||
tonic = { version = "*", default-features = false, features = [
|
tonic = { version = "0.14.2", default-features = false, features = [
|
||||||
"codegen",
|
"codegen",
|
||||||
"prost",
|
|
||||||
] }
|
] }
|
||||||
prost = "0.13"
|
prost = "0.14"
|
||||||
tonic-web-wasm-client = "0.7"
|
prost-types = "0.14"
|
||||||
|
tonic-web-wasm-client = "0.8"
|
||||||
web-sys = { version = "0.3.77", features = ["Storage", "Window"] }
|
web-sys = { version = "0.3.77", features = ["Storage", "Window"] }
|
||||||
|
tokio = "1.49.0"
|
||||||
|
tonic-prost = "0.14.2"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
tonic-build = { version = "*", default-features = false, features = ["prost"] }
|
tonic-prost-build = { version = "0.14.2"}
|
||||||
dotenv = "0.15.0"
|
dotenv = "0.15.0"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
|||||||
@@ -4,15 +4,14 @@ use std::fs::File;
|
|||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
// tonic_build::configure()
|
tonic_prost_build::configure()
|
||||||
// .build_server(false)
|
.build_server(false)
|
||||||
// .build_client(true)
|
.build_client(true)
|
||||||
// .compile_protos(
|
.build_transport(false)
|
||||||
// &[
|
.compile_protos(
|
||||||
// "",
|
&["../AZKiServer/Protos/azki.proto", "../AZKiServer/Protos/types.proto"],
|
||||||
// ],
|
&["../AZKiServer"],
|
||||||
// &[""],
|
)?;
|
||||||
// )?;
|
|
||||||
forward_env();
|
forward_env();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,8 +4,14 @@ mod app;
|
|||||||
mod components;
|
mod components;
|
||||||
mod env;
|
mod env;
|
||||||
mod route;
|
mod route;
|
||||||
|
mod rpc;
|
||||||
mod views;
|
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() {
|
fn main() {
|
||||||
dioxus::launch(App);
|
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