diff --git a/alterego/.DS_Store b/alterego/.DS_Store deleted file mode 100644 index e37c505..0000000 Binary files a/alterego/.DS_Store and /dev/null differ diff --git a/alterego/.drone.jsonnet b/alterego/.drone.jsonnet deleted file mode 100644 index ccecdba..0000000 --- a/alterego/.drone.jsonnet +++ /dev/null @@ -1,93 +0,0 @@ -local image = std.extVar("image"); -local app_name = std.extVar("app_name"); -local target_arch = std.extVar("target_arch"); - -local flags = " --release --target=" + target_arch; - -local volume(name, path) = { - name: name, - path: path, -}; - -local volumes = [ - volume("cargo", "/usr/local/cargo"), - volume("target", "/cache/target"), - volume("rustup", "/usr/local/rustup"), -]; - -local step(name, depends=[], commands=[], env={}) = { - name: name, - volumes: volumes, - image: image, - depends_on: depends, - commands: commands, - environment: env + { - CARGO_TARGET_DIR: "/cache/target", - APP_NAME: app_name, - }, -}; - -local temp_volume(name) = { - name: name, - temp: {}, -}; - -local host_volume(name, path) = { - name: name, - host: { - path: path, - }, -}; - -{ - kind: "pipeline", - type: "docker", - name: "default", - platform: { - "os": "linux", - "arch": "arm", - }, - - steps: [ - step( - "validate", - commands=["cargo test" + flags], - ), - step( - "test", - depends=["validate"], - commands=["cargo test" + flags], - ), - step( - "build", - depends=["test"], - commands=["cargo build" + flags], - env={ - GIT_REVISION: "${DRONE_COMMIT:0:8}", - GIT_BRANCH: "${DRONE_COMMIT_BRANCH}", - }, - ), - step( - "deploy", - depends=["build"], - commands=["sh scripts/deploy.sh"], - env={ - TARGET_DIR: "/cache/target/" + target_arch + "/release", - SSH_PRIVATE_KEY: {"from_secret": "ssh_pk_base64"}, - SSH_USER: {"from_secret": "SSH_USER"}, - }, - ), - ], - - volumes: [ - temp_volume("target"), - host_volume("cargo", "/home/pi/.cargo"), - host_volume("rustup", "/home/pi/.rustup"), - ], - - // BUG: thid does not add. - // environment: { - // CARGO_TARGET_DIR: "/cache/target/", - // APP_NAME: "deploytest", - // } -} diff --git a/alterego/.drone.yml b/alterego/.drone.yml deleted file mode 100644 index a6d9694..0000000 --- a/alterego/.drone.yml +++ /dev/null @@ -1,98 +0,0 @@ ---- -kind: pipeline -type: docker -name: default - -platform: - os: linux - arch: arm - -steps: -- name: validate - image: rust:1.49 - commands: - - cargo test --release --target=armv7-unknown-linux-gnueabihf - environment: - APP_NAME: altherego - CARGO_TARGET_DIR: /cache/target - volumes: - - name: cargo - path: /usr/local/cargo - - name: target - path: /cache/target - - name: rustup - path: /usr/local/rustup - -- name: test - image: rust:1.49 - commands: - - cargo test --release --target=armv7-unknown-linux-gnueabihf - environment: - APP_NAME: altherego - CARGO_TARGET_DIR: /cache/target - volumes: - - name: cargo - path: /usr/local/cargo - - name: target - path: /cache/target - - name: rustup - path: /usr/local/rustup - depends_on: - - validate - -- name: build - image: rust:1.49 - commands: - - cargo build --release --target=armv7-unknown-linux-gnueabihf - environment: - APP_NAME: altherego - CARGO_TARGET_DIR: /cache/target - GIT_BRANCH: ${DRONE_COMMIT_BRANCH} - GIT_REVISION: ${DRONE_COMMIT:0:8} - volumes: - - name: cargo - path: /usr/local/cargo - - name: target - path: /cache/target - - name: rustup - path: /usr/local/rustup - depends_on: - - test - -- name: deploy - image: rust:1.49 - commands: - - sh scripts/deploy.sh - environment: - APP_NAME: altherego - CARGO_TARGET_DIR: /cache/target - SSH_PRIVATE_KEY: - from_secret: ssh_pk_base64 - SSH_USER: - from_secret: SSH_USER - TARGET_DIR: /cache/target/armv7-unknown-linux-gnueabihf/release - volumes: - - name: cargo - path: /usr/local/cargo - - name: target - path: /cache/target - - name: rustup - path: /usr/local/rustup - depends_on: - - build - -volumes: -- name: target - temp: {} -- name: cargo - host: - path: /home/pi/.cargo -- name: rustup - host: - path: /home/pi/.rustup - ---- -kind: signature -hmac: a942d89af2c38916d55ebe377709febf08145ce8e08a2b585dda8a1c251eaca0 - -... diff --git a/alterego/Cargo.toml b/alterego/Cargo.toml deleted file mode 100644 index faa1ea5..0000000 --- a/alterego/Cargo.toml +++ /dev/null @@ -1,16 +0,0 @@ -[package] -name = "alterego" -version = "0.1.0" -authors = ["Aleksandr Trushkin "] -edition = "2018" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -anyhow = {workspace = true} -futures = {workspace = true} -log = {workspace = true} -reqwest = {workspace = true} -serde = {workspace = true, features = ["derive"]} -serde_json = {workspace = true} -tokio = {workspace = true} diff --git a/alterego/build.rs b/alterego/build.rs deleted file mode 100644 index 9b79ad7..0000000 --- a/alterego/build.rs +++ /dev/null @@ -1,41 +0,0 @@ -use std::env; - -fn main() { - let rev = get_value_from_env("GIT_VERSION") - .or_else(|| get_value_from_command("git", &["rev-parse", "--short", "HEAD"])) - .unwrap_or_else(|| "unknown".to_owned()); - - let branch = get_value_from_env("GIT_BRANCH") - .or_else(|| get_value_from_command("git", &["rev-parse", "--abbrev-ref", "HEAD"])) - .unwrap_or_else(|| "unknown".to_owned()); - - println!("cargo:rustc-env=GIT_REVISION={}", rev); - println!("cargo:rustc-env=GIT_BRANCH={}", branch); - println!("cargo:rerun-if-env-changed=GIT_REVISION"); -} - -fn get_value_from_env(key: &str) -> Option { - env::var(key).map_or_else(|_| None, Some) -} - -fn get_value_from_command, S: AsRef>( - cmd: &str, - args: I, -) -> Option { - std::process::Command::new(cmd) - .args(args) - .output() - .map_or_else( - |_| None, - |out| { - if !out.status.success() { - return None; - } - - match std::str::from_utf8(&out.stdout) { - Ok(value) => Some(value.to_owned()), - Err(_) => None, - } - }, - ) -} diff --git a/alterego/makefile b/alterego/makefile deleted file mode 100644 index f9fa345..0000000 --- a/alterego/makefile +++ /dev/null @@ -1,40 +0,0 @@ -export DOCKER_BUILDKIT=1 - -DOCKERFLAGS:=-it --rm \ - -v "${PWD}":"/app" \ - --workdir "/app" \ - -e "PWD=/app" - -DOCKERIMG:="rust-build-env:V1" - -APP_NAME:=altherego -IMAGE:=rust:1.49 -TARGET_ARCH:=armv7-unknown-linux-gnueabihf - -image: - docker build -t rust-build-env:V1 . -.PHONY: image - -ARM_PREFIX:=CARGO_TARGET_ARM_UNKNOWN_LINUX_MUSLEABIHF_LINKER=arm-linux-gnueabihf-ld \ - REALGCC=arm-linux-gnueabihf-gcc-8 \ - TARGET_CC=musl-gcc - -build_debug_arm: - ${ARM_PREFIX} cargo build --target=armv7-unknown-linux-musleabihf -.PHONY: build_debug_arm - -build_release_arm: - docker run ${DOCKERFLAGS} ${DOCKERIMG} /bin/sh -c 'cargo build --release --target=armv7-unknown-linux-gnueabihf' -.PHONY: build_release_arm - -docker_build_release_arm: - docker run ${DOCKERFLAGS} ${DOCKERIMG} make build_release_arm - -dronefile: - drone jsonnet \ - --format \ - -V app_name=${APP_NAME} \ - -V image=${IMAGE} \ - -V target_arch=${TARGET_ARCH} - drone sign frx/altherego --save -.PHONY: dronefile diff --git a/alterego/src/lib.rs b/alterego/src/lib.rs deleted file mode 100644 index e894b90..0000000 --- a/alterego/src/lib.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod telegram; diff --git a/alterego/src/main.rs b/alterego/src/main.rs deleted file mode 100644 index bd8abe8..0000000 --- a/alterego/src/main.rs +++ /dev/null @@ -1,70 +0,0 @@ -use alterego::telegram; - -use tokio::runtime; -const BOT_TOKEN: &str = "170515067:AAElDJ8Sq_oIqo9WaL4DKvUr13nSEIdHCYs"; - -fn main() -> anyhow::Result<()> { - println!("Hello, world!"); - - let rt = runtime::Builder::new_current_thread() - .enable_io() - .enable_time() - .build() - .expect("making runtime"); - - rt.block_on(app())?; - - Ok(()) -} - -use futures::StreamExt; - -async fn app() -> anyhow::Result<()> { - let bot = telegram::bot::Client::new(BOT_TOKEN.to_owned()); - - let mut stream = bot.updates_stream(); - while let Some(update) = stream.next().await { - let update = update?; - - println!("{:?}", update); - - handle_update(update); - } - - Ok(()) -} - -use log::{debug, trace, warn}; -use telegram::types::UpdateKind; - -fn handle_update(update: telegram::types::Update) { - match update.kind { - UpdateKind::Message(msg) => { - let text = msg.text.unwrap_or_default(); - - if !text.starts_with('/') { - trace!("it's not a command, skipping"); - return; - } - - match text.as_str() { - "/help" => { - println!("help command called"); - } - "/temp" => { - println!("temp command called"); - } - "/versionrequest" => {} - other => { - println!("unknown command {}", other); - } - } - } - UpdateKind::EditedMessage(msg) => { - debug!("edited message: {:?}", msg); - } - UpdateKind::Undefined => { - warn!("message udentified"); - } - } -} diff --git a/alterego/src/telegram/bot.rs b/alterego/src/telegram/bot.rs deleted file mode 100644 index 0550bf0..0000000 --- a/alterego/src/telegram/bot.rs +++ /dev/null @@ -1,184 +0,0 @@ -use super::types::*; - -use std::{ - cmp::max, - collections::VecDeque, - future::Future, - pin::Pin, - sync::atomic::{AtomicI32, Ordering}, - task::{Context, Poll}, -}; - -use log::{debug, trace}; -use reqwest; - -const TELEGRAM_URL: &str = "https://api.telegram.org"; -const HTTP_CLIENT: &str = "alterego-http-client/1.0"; - -#[derive(Debug)] -pub enum BotError { - API(String), -} - -impl std::fmt::Display for BotError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let text = match self { - BotError::API(msg) => format!("api error: {}", msg), - }; - - write!(f, "{}", text) - } -} - -impl std::error::Error for BotError {} - -#[derive(Debug, Clone)] -/// Client provides API for communicating with Telegram Bot API. -pub struct Client { - pub token: String, - pub client: reqwest::Client, -} - -impl Client { - pub fn new(token: String) -> Self { - let client = reqwest::ClientBuilder::default() - .connect_timeout(std::time::Duration::from_secs(5)) - .https_only(true) - .user_agent(HTTP_CLIENT) - .build() - .expect("building http client"); - - Self { token, client } - } - - fn make_url(&self, method: &str) -> String { - format!("{}/bot{}/{}", TELEGRAM_URL, self.token, method) - } - - fn fetch_updates( - &self, - offset: i32, - ) -> impl Future>>> { - let client = self.clone(); - async move { client.get_updates(offset).await } - } - - pub async fn get_updates(&self, offset: i32) -> anyhow::Result>> { - const METHOD: &str = "getUpdates"; - - trace!("getting updates"); - - let url = { - let mut url = reqwest::Url::parse(&self.make_url(METHOD))?; - url.set_query(Some(format!("offset={}", offset).as_str())); - url - }; - - debug!("requesting: {}", url.as_str()); - let body = self.client.get(url).send().await?.bytes().await?; - - let response: Response = serde_json::from_reader(&body[..])?; - if response.is_err() { - debug!("response finished with error"); - return Err(anyhow::anyhow!(BotError::API( - response.description.unwrap() - ))); - }; - - Ok(response.result) - } - - pub fn updates_stream(&self) -> ClientUpdateStream { - ClientUpdateStream::new(self) - } - - pub async fn reply(&self) -> anyhow::Result<()> { - todo!("soon") - } -} - -type PinnedRequest = Pin>>> + Send>>; - -pub struct ClientUpdateStream { - client: Client, - next_id: AtomicI32, - buffer: VecDeque, - pinned_request: Option, -} - -impl ClientUpdateStream { - pub fn new(client: &Client) -> Self { - Self { - client: client.clone(), - next_id: AtomicI32::new(0), - buffer: VecDeque::new(), - pinned_request: None, - } - } -} - -impl futures::Stream for ClientUpdateStream { - type Item = anyhow::Result; - - /// poll_next fetches updates from client and appends it to - /// buffer. - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let myself = self.get_mut(); - - let mut current_id = myself.next_id.load(Ordering::SeqCst); - - if let Some(value) = myself.buffer.pop_front() { - return Poll::Ready(Some(Ok(value))); - }; - - // Check the current state of myself. - // In case request is being processed, return Pending; - // In case request is ready, insert updates and return Ok(true); - // In case there is no request or updates are empty, return Ok(false); - // Ok(state), where states defines whether new request should be - // created or not. - let result = match myself.pinned_request { - None => Ok(false), - Some(ref mut request) => { - let request = request.as_mut(); - let polled_request = request.poll(cx); - - match polled_request { - Poll::Pending => return Poll::Pending, - Poll::Ready(Ok(None)) => Ok(false), - Poll::Ready(Ok(Some(ref updates))) if updates.is_empty() => Ok(false), - Poll::Ready(Ok(Some(updates))) => { - for update in updates { - current_id = max(current_id, update.id + 1); - myself.buffer.push_back(update); - } - - Ok(true) - } - Poll::Ready(Err(err)) => Err(err), - } - } - }; - - myself.next_id.store(current_id, Ordering::SeqCst); - - match result { - Ok(true) => { - myself.pinned_request = None; - Pin::new(myself).poll_next(cx) - } - Ok(false) => { - let next_request = myself.client.fetch_updates(current_id); - myself.pinned_request = Some(Box::pin(next_request)); - - Pin::new(myself).poll_next(cx) - } - Err(err) => { - let next_request = myself.client.fetch_updates(current_id); - myself.pinned_request = Some(Box::pin(next_request)); - - Poll::Ready(Some(Err(err))) - } - } - } -} diff --git a/alterego/src/telegram/mod.rs b/alterego/src/telegram/mod.rs deleted file mode 100644 index 33547fc..0000000 --- a/alterego/src/telegram/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod bot; -pub mod types; diff --git a/alterego/src/telegram/types.rs b/alterego/src/telegram/types.rs deleted file mode 100644 index 77d9fb0..0000000 --- a/alterego/src/telegram/types.rs +++ /dev/null @@ -1,63 +0,0 @@ -use serde::Deserialize; - -#[derive(Debug, Deserialize)] -pub struct Response { - pub ok: bool, - pub error_code: Option, - pub description: Option, - pub result: Option>, -} - -impl Response { - pub fn is_err(&self) -> bool { - !self.ok - } -} - -#[derive(Debug, Deserialize)] -pub struct Update { - #[serde(rename = "update_id")] - pub id: i32, - - #[serde(flatten)] - pub kind: UpdateKind, -} - -#[derive(Debug, Deserialize)] -pub enum UpdateKind { - #[serde(rename = "message")] - Message(Message), - - #[serde(rename = "edited_message")] - EditedMessage(Message), - - Undefined, -} - -#[derive(Debug, Deserialize)] -pub struct Message { - pub message_id: i32, - pub from: Option, - pub sender_chat: Option, - pub date: i64, - pub chat: Chat, - pub text: Option, -} - -#[derive(Debug, Deserialize)] -pub struct User { - pub id: i32, - pub is_bot: bool, - pub first_name: String, - pub last_name: Option, - pub username: Option, -} - -#[derive(Debug, Deserialize)] -pub struct Chat { - pub id: i32, - #[serde(alias = "type")] - pub chat_type: String, - pub title: Option, - pub username: Option, -}