summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore22
-rw-r--r--Cargo.toml14
-rw-r--r--Containerfile37
-rw-r--r--LICENSE21
-rw-r--r--build.rs4
-rw-r--r--proto/countah.proto13
-rw-r--r--src/main.rs57
7 files changed, 168 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..ab951f8
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,22 @@
+# ---> Rust
+# Generated by Cargo
+# will have compiled files and executables
+debug/
+target/
+
+# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
+# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
+Cargo.lock
+
+# These are backup files generated by rustfmt
+**/*.rs.bk
+
+# MSVC Windows builds of rustc generate these, which store debugging information
+*.pdb
+
+# RustRover
+# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
+# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
+# and can be added to the global gitignore or merged into this file. For a more nuclear
+# option (not recommended) you can uncomment the following to ignore the entire idea folder.
+#.idea/
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..1be61ee
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,14 @@
+[package]
+name = "pubd"
+version = "0.1.0"
+edition = "2024"
+
+[dependencies]
+prost = "0.14.3"
+tokio = { version = "1.49.0", features = ["macros", "rt-multi-thread"] }
+tokio-stream = "0.1.18"
+tonic = "0.14.2"
+tonic-prost = "0.14.2"
+
+[build-dependencies]
+tonic-prost-build = "0.14.2"
diff --git a/Containerfile b/Containerfile
new file mode 100644
index 0000000..4c8852b
--- /dev/null
+++ b/Containerfile
@@ -0,0 +1,37 @@
+# A multi-stage container file for the pubd application.
+
+#
+# Build stage
+#
+
+FROM rust:1.91-alpine3.23 AS builder
+
+RUN apk add --no-cache musl-dev protobuf-dev
+
+WORKDIR /app
+
+COPY Cargo.toml Cargo.lock* ./
+
+COPY proto ./proto
+
+COPY build.rs ./
+
+COPY src ./src
+
+RUN cargo build --release
+
+#
+# Run stage
+#
+
+FROM alpine:latest
+
+RUN apk add --no-cache libgcc
+
+WORKDIR /app
+
+COPY --from=builder /app/target/release/pubd /app/pubd
+
+EXPOSE 60069
+
+CMD ["/app/pubd"]
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..52686ad
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2025 Closed Circuit Consulting
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE. \ No newline at end of file
diff --git a/build.rs b/build.rs
new file mode 100644
index 0000000..5005f6f
--- /dev/null
+++ b/build.rs
@@ -0,0 +1,4 @@
+fn main() -> Result<(), Box<dyn std::error::Error>> {
+ tonic_prost_build::configure().compile_protos(&["proto/countah.proto"], &["proto/"])?;
+ Ok(())
+}
diff --git a/proto/countah.proto b/proto/countah.proto
new file mode 100644
index 0000000..698c3db
--- /dev/null
+++ b/proto/countah.proto
@@ -0,0 +1,13 @@
+syntax = "proto3";
+
+package unit.countah.v0;
+
+service Countah {
+ rpc Counter (CounterRequest) returns (stream CounterResponse);
+}
+
+message CounterRequest { }
+
+message CounterResponse {
+ fixed64 count = 1;
+}
diff --git a/src/main.rs b/src/main.rs
new file mode 100644
index 0000000..fa3657c
--- /dev/null
+++ b/src/main.rs
@@ -0,0 +1,57 @@
+pub mod pb {
+ tonic::include_proto!("unit.countah.v0");
+}
+
+use std::pin::Pin;
+use tokio_stream::Stream;
+use tokio_stream::wrappers::ReceiverStream;
+use tonic::{Request, Response, Status, transport::Server};
+
+use crate::pb::{CounterRequest, CounterResponse};
+
+#[derive(Debug, Default)]
+pub struct PubdServer {}
+
+#[tonic::async_trait]
+impl pb::countah_server::Countah for PubdServer {
+ type CounterStream = Pin<Box<dyn Stream<Item = Result<CounterResponse, Status>> + Send>>;
+
+ async fn counter(
+ &self,
+ _request: Request<CounterRequest>,
+ ) -> Result<Response<Self::CounterStream>, Status> {
+ let (tx, rx) = tokio::sync::mpsc::channel(128);
+
+ tokio::spawn(async move {
+ let mut count: u64 = 0;
+ loop {
+ count += 1;
+ let response = CounterResponse { count };
+
+ if tx.send(Ok(response)).await.is_err() {
+ break;
+ }
+
+ tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
+ }
+ });
+
+ let stream = ReceiverStream::new(rx);
+ Ok(Response::new(Box::pin(stream)))
+ }
+}
+
+#[tokio::main]
+async fn main() -> Result<(), Box<dyn std::error::Error>> {
+ let addr = "0.0.0.0:60069".parse().unwrap();
+ let server = PubdServer::default();
+
+ println!("Listening on {}", addr);
+
+ Server::builder()
+ .add_service(pb::countah_server::CountahServer::new(server))
+ .serve(addr)
+ .await?;
+
+ Ok(())
+}