mirror of
https://github.com/mii443/ncb-chat.git
synced 2025-08-22 16:15:27 +00:00
init
This commit is contained in:
2
.dockerignore
Normal file
2
.dockerignore
Normal file
@ -0,0 +1,2 @@
|
||||
target
|
||||
audio
|
47
.github/workflows/build.yml
vendored
Normal file
47
.github/workflows/build.yml
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
on:
|
||||
push:
|
||||
branches-ignore:
|
||||
- '**'
|
||||
tags:
|
||||
- 'v*'
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
name: Checkout
|
||||
- uses: docker/metadata-action@v3
|
||||
id: meta
|
||||
with:
|
||||
images: ghcr.io/morioka22/ncb-ping
|
||||
tags: |
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
- uses: docker/login-action@v1
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: morioka22
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
|
||||
- name: Cache Docker layers
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: /tmp/.buildx-cache
|
||||
key: ${{ runner.os }}-buildx-${{ github.sha }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-buildx-
|
||||
|
||||
- uses: docker/build-push-action@v2
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
cache-from: type=local,src=/tmp/.buildx-cache
|
||||
cache-to: type=local,dest=/tmp/.buildx-cache-new,mode=max
|
||||
- name: Move cache
|
||||
run: |
|
||||
rm -rf /tmp/.buildx-cache
|
||||
mv /tmp/.buildx-cache-new /tmp/.buildx-cache
|
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
Cargo.lock
|
||||
/target
|
||||
config.toml
|
||||
*.swp
|
26
Cargo.toml
Normal file
26
Cargo.toml
Normal file
@ -0,0 +1,26 @@
|
||||
[package]
|
||||
name = "ncb-ping"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
serde_json = "1.0"
|
||||
serde = "1.0"
|
||||
toml = "0.5"
|
||||
async-trait = "0.1.57"
|
||||
chrono = "0.4.23"
|
||||
|
||||
[dependencies.uuid]
|
||||
version = "0.8"
|
||||
features = ["serde", "v4"]
|
||||
|
||||
[dependencies.serenity]
|
||||
version = "0.11.5"
|
||||
features = ["builder", "cache", "client", "gateway", "model", "utils", "unstable_discord_api", "collector", "rustls_backend", "framework", "voice"]
|
||||
|
||||
|
||||
[dependencies.tokio]
|
||||
version = "1.0"
|
||||
features = ["macros", "rt-multi-thread", "sync"]
|
19
Dockerfile
Normal file
19
Dockerfile
Normal file
@ -0,0 +1,19 @@
|
||||
FROM lukemathwalker/cargo-chef:latest-rust-1 AS chef
|
||||
WORKDIR app
|
||||
|
||||
FROM chef AS planner
|
||||
COPY . .
|
||||
RUN cargo chef prepare --recipe-path recipe.json
|
||||
|
||||
FROM chef AS builder
|
||||
COPY --from=planner /app/recipe.json recipe.json
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends libssl-dev pkg-config gcc && apt-get -y clean
|
||||
RUN cargo chef cook --release --recipe-path recipe.json
|
||||
COPY . .
|
||||
RUN cargo build --release
|
||||
|
||||
FROM debian:bullseye-slim AS runtime
|
||||
WORKDIR /ncb-ping
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends ca-certificates libssl-dev && apt-get -y clean
|
||||
COPY --from=builder /app/target/release/ncb-ping /usr/local/bin
|
||||
ENTRYPOINT ["/usr/local/bin/ncb-ping"]
|
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 mii8080
|
||||
|
||||
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.
|
9
docker-compose.yml
Normal file
9
docker-compose.yml
Normal file
@ -0,0 +1,9 @@
|
||||
version: '3'
|
||||
|
||||
services:
|
||||
ncb-tts-r2:
|
||||
container_name: ncb-tts-r2
|
||||
image: ghcr.io/morioka22/ncb-tts-r2:1.2
|
||||
environment:
|
||||
- NCB_TOKEN=YOUR_BOT_TOKEN
|
||||
- NCB_APP_ID=YOUR_BOT_ID
|
28
manifest/ncb-ping.yaml
Normal file
28
manifest/ncb-ping.yaml
Normal file
@ -0,0 +1,28 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: ncb-ping-deployment
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: ncb-ping
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: ncb-ping
|
||||
spec:
|
||||
containers:
|
||||
- name: ping
|
||||
image: ghcr.io/morioka22/ncb-ping
|
||||
env:
|
||||
- name: NCB_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: ncb-secret
|
||||
key: BOT_TOKEN
|
||||
- name: NCB_APP_ID
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: ncb-secret
|
||||
key: APP_ID
|
7
src/config.rs
Normal file
7
src/config.rs
Normal file
@ -0,0 +1,7 @@
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct Config {
|
||||
pub token: String,
|
||||
pub application_id: u64,
|
||||
}
|
24
src/data.rs
Normal file
24
src/data.rs
Normal file
@ -0,0 +1,24 @@
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
|
||||
use chrono::{DateTime, Utc};
|
||||
use serenity::{
|
||||
futures::lock::Mutex,
|
||||
model::prelude::{ChannelId, Message, UserId},
|
||||
prelude::TypeMapKey,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Ping {
|
||||
pub channel: ChannelId,
|
||||
pub user_id: UserId,
|
||||
pub author: UserId,
|
||||
pub message: Message,
|
||||
pub time: DateTime<Utc>,
|
||||
pub args: Vec<String>,
|
||||
}
|
||||
|
||||
pub struct PingData;
|
||||
|
||||
impl TypeMapKey for PingData {
|
||||
type Value = Arc<Mutex<HashMap<UserId, Ping>>>;
|
||||
}
|
23
src/event_handler.rs
Normal file
23
src/event_handler.rs
Normal file
@ -0,0 +1,23 @@
|
||||
use serenity::{
|
||||
async_trait,
|
||||
client::{Context, EventHandler},
|
||||
model::{
|
||||
channel::Message,
|
||||
gateway::Ready,
|
||||
},
|
||||
};
|
||||
|
||||
use crate::events;
|
||||
|
||||
pub struct Handler;
|
||||
|
||||
#[async_trait]
|
||||
impl EventHandler for Handler {
|
||||
async fn message(&self, ctx: Context, message: Message) {
|
||||
events::message_receive::message(ctx, message).await;
|
||||
}
|
||||
|
||||
async fn ready(&self, ctx: Context, ready: Ready) {
|
||||
events::ready::ready(ctx, ready).await
|
||||
}
|
||||
}
|
58
src/events/message_receive.rs
Normal file
58
src/events/message_receive.rs
Normal file
@ -0,0 +1,58 @@
|
||||
use chrono::Utc;
|
||||
use serenity::{model::prelude::Message, prelude::Context};
|
||||
|
||||
use crate::data::{PingData, Ping};
|
||||
|
||||
pub async fn message(ctx: Context, message: Message) {
|
||||
if message.author.bot {
|
||||
return;
|
||||
}
|
||||
|
||||
let guild_id = message.guild(&ctx.cache);
|
||||
|
||||
if let None = guild_id {
|
||||
return;
|
||||
}
|
||||
|
||||
let storage_lock = {
|
||||
let data_read = ctx.data.read().await;
|
||||
data_read
|
||||
.get::<PingData>()
|
||||
.expect("Cannot get PingData")
|
||||
.clone()
|
||||
};
|
||||
|
||||
if message.mentions.len() == 1 {
|
||||
let user = message.mentions.first().unwrap();
|
||||
let m = format!("PING {} ({}) 56(84) bytes of data.", user.name, user.id.0);
|
||||
let ping_message = message.reply(&ctx.http, m).await.unwrap();
|
||||
|
||||
let ping = Ping {
|
||||
channel: message.channel_id,
|
||||
user_id: user.id,
|
||||
author: message.author.id,
|
||||
time: Utc::now(),
|
||||
message: ping_message,
|
||||
args: vec![]
|
||||
};
|
||||
|
||||
let mut storage = storage_lock.lock().await;
|
||||
storage.insert(user.id, ping.clone());
|
||||
}
|
||||
|
||||
{
|
||||
let mut storage = storage_lock.lock().await;
|
||||
if !storage.contains_key(&message.author.id) {
|
||||
return;
|
||||
}
|
||||
let ping = storage.get_mut(&message.author.id).unwrap();
|
||||
|
||||
if ping.channel == message.channel_id {
|
||||
let user = ping.user_id.to_user(&ctx.http).await.unwrap();
|
||||
let time = Utc::now() - ping.time;
|
||||
ping.message.edit(&ctx.http, |f| f.content(format!("--- {} ping statistics ---\n1 packets transmitted, 1 received, 0% packet loss, time {}ms", user.name, time.num_milliseconds()))).await.unwrap();
|
||||
message.channel_id.send_message(&ctx.http, |f| f.content(format!("<@{}>", ping.author.0))).await.unwrap();
|
||||
storage.remove(&message.author.id);
|
||||
}
|
||||
}
|
||||
}
|
2
src/events/mod.rs
Normal file
2
src/events/mod.rs
Normal file
@ -0,0 +1,2 @@
|
||||
pub mod message_receive;
|
||||
pub mod ready;
|
5
src/events/ready.rs
Normal file
5
src/events/ready.rs
Normal file
@ -0,0 +1,5 @@
|
||||
use serenity::{model::prelude::Ready, prelude::Context};
|
||||
|
||||
pub async fn ready(_: Context, ready: Ready) {
|
||||
println!("{} is connected!", ready.user.name);
|
||||
}
|
66
src/main.rs
Normal file
66
src/main.rs
Normal file
@ -0,0 +1,66 @@
|
||||
mod config;
|
||||
mod data;
|
||||
mod event_handler;
|
||||
mod events;
|
||||
|
||||
use std::{collections::HashMap, env, sync::Arc};
|
||||
|
||||
use config::Config;
|
||||
use data::PingData;
|
||||
use event_handler::Handler;
|
||||
use serenity::{
|
||||
client::Client, framework::StandardFramework, futures::lock::Mutex, prelude::GatewayIntents,
|
||||
};
|
||||
|
||||
/// Create discord client
|
||||
///
|
||||
/// Example:
|
||||
/// ```rust
|
||||
/// let client = create_client("!", "BOT_TOKEN", 123456789123456789).await;
|
||||
///
|
||||
/// client.start().await;
|
||||
/// ```
|
||||
async fn create_client(prefix: &str, token: &str, id: u64) -> Result<Client, serenity::Error> {
|
||||
let framework = StandardFramework::new().configure(|c| c.with_whitespace(true).prefix(prefix));
|
||||
|
||||
Client::builder(token, GatewayIntents::all())
|
||||
.event_handler(Handler)
|
||||
.application_id(id)
|
||||
.framework(framework)
|
||||
.await
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
// Load config
|
||||
let config = {
|
||||
let config = std::fs::read_to_string("./config.toml");
|
||||
if let Ok(config) = config {
|
||||
toml::from_str::<Config>(&config).expect("Cannot load config file.")
|
||||
} else {
|
||||
let token = env::var("NCB_TOKEN").unwrap();
|
||||
let application_id = env::var("NCB_APP_ID").unwrap();
|
||||
|
||||
Config {
|
||||
token,
|
||||
application_id: u64::from_str_radix(&application_id, 10).unwrap(),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Create discord client
|
||||
let mut client = create_client("p.", &config.token, config.application_id)
|
||||
.await
|
||||
.expect("Err creating client");
|
||||
|
||||
// Create TTS storage
|
||||
{
|
||||
let mut data = client.data.write().await;
|
||||
data.insert::<PingData>(Arc::new(Mutex::new(HashMap::default())));
|
||||
}
|
||||
|
||||
// Run client
|
||||
if let Err(why) = client.start().await {
|
||||
println!("Client error: {:?}", why);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user