altherego remove

This commit is contained in:
2023-02-26 18:00:23 +03:00
parent 24185f677e
commit bc2eb34d9a
11 changed files with 0 additions and 608 deletions

BIN
alterego/.DS_Store vendored

Binary file not shown.

View File

@ -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",
// }
}

View File

@ -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
...

View File

@ -1,16 +0,0 @@
[package]
name = "alterego"
version = "0.1.0"
authors = ["Aleksandr Trushkin <aleksandr.trushkin@rt.ru>"]
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}

View File

@ -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<String> {
env::var(key).map_or_else(|_| None, Some)
}
fn get_value_from_command<I: IntoIterator<Item = S>, S: AsRef<std::ffi::OsStr>>(
cmd: &str,
args: I,
) -> Option<String> {
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,
}
},
)
}

View File

@ -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

View File

@ -1 +0,0 @@
pub mod telegram;

View File

@ -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");
}
}
}

View File

@ -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<Output = anyhow::Result<Option<Vec<Update>>>> {
let client = self.clone();
async move { client.get_updates(offset).await }
}
pub async fn get_updates(&self, offset: i32) -> anyhow::Result<Option<Vec<Update>>> {
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<Update> = 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<Box<dyn Future<Output = anyhow::Result<Option<Vec<Update>>>> + Send>>;
pub struct ClientUpdateStream {
client: Client,
next_id: AtomicI32,
buffer: VecDeque<Update>,
pinned_request: Option<PinnedRequest>,
}
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<Update>;
/// poll_next fetches updates from client and appends it to
/// buffer.
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
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)))
}
}
}
}

View File

@ -1,2 +0,0 @@
pub mod bot;
pub mod types;

View File

@ -1,63 +0,0 @@
use serde::Deserialize;
#[derive(Debug, Deserialize)]
pub struct Response<T> {
pub ok: bool,
pub error_code: Option<i32>,
pub description: Option<String>,
pub result: Option<Vec<T>>,
}
impl<T> Response<T> {
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<User>,
pub sender_chat: Option<Chat>,
pub date: i64,
pub chat: Chat,
pub text: Option<String>,
}
#[derive(Debug, Deserialize)]
pub struct User {
pub id: i32,
pub is_bot: bool,
pub first_name: String,
pub last_name: Option<String>,
pub username: Option<String>,
}
#[derive(Debug, Deserialize)]
pub struct Chat {
pub id: i32,
#[serde(alias = "type")]
pub chat_type: String,
pub title: Option<String>,
pub username: Option<String>,
}