chore: remove guestbook, gazebot (now unused)
This commit is contained in:
parent
629a4d8f0e
commit
84382e5b05
34
flake.nix
34
flake.nix
@ -3,8 +3,6 @@
|
||||
inputs.nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
|
||||
inputs.systems.url = "github:nix-systems/x86_64-linux";
|
||||
inputs.naked-shell.url = "github:yusdacra/mk-naked-shell";
|
||||
inputs.sbt-derivation.url = "github:zaninime/sbt-derivation";
|
||||
inputs.sbt-derivation.inputs.nixpkgs.follows = "nixpkgs";
|
||||
|
||||
outputs = inp:
|
||||
inp.parts.lib.mkFlake {inputs = inp;} {
|
||||
@ -17,7 +15,7 @@
|
||||
system,
|
||||
...
|
||||
}: let
|
||||
pkgs = inp.nixpkgs.legacyPackages.${system}.appendOverlays [inp.sbt-derivation.overlays.default];
|
||||
pkgs = inp.nixpkgs.legacyPackages.${system};
|
||||
packageJson = builtins.fromJSON (builtins.readFile ./package.json);
|
||||
in {
|
||||
devShells.default = config.mk-naked-shell.lib.mkNakedShell {
|
||||
@ -26,7 +24,6 @@
|
||||
nodejs-slim_latest bun
|
||||
nodePackages.svelte-language-server
|
||||
nodePackages.typescript-language-server
|
||||
sbt
|
||||
];
|
||||
shellHook = ''
|
||||
export PATH="$PATH:$PWD/node_modules/.bin"
|
||||
@ -90,35 +87,6 @@
|
||||
runHook postInstall
|
||||
'';
|
||||
};
|
||||
packages.guestbook-jar = pkgs.mkSbtDerivation rec {
|
||||
pname = "guestbook";
|
||||
version = "0.0.1-jar";
|
||||
depsSha256 = "sha256-hIGZTEZpqgBuo6VGgZ6dQd5kK0RLVNy5REVBBYA3Gak=";
|
||||
src = ./guestbook;
|
||||
buildPhase = ''
|
||||
sbt assembly
|
||||
mkdir -p ./target/graalvm-native-image
|
||||
'';
|
||||
installPhase = ''
|
||||
mkdir -p $out
|
||||
cp target/scala-3.4.2/${pname}-assembly-0.0.1-SNAPSHOT.jar $out/${pname}.jar
|
||||
'';
|
||||
nativeBuildInputs = [
|
||||
pkgs.graalvm-ce
|
||||
];
|
||||
};
|
||||
packages.guestbook = pkgs.stdenv.mkDerivation rec {
|
||||
inherit (config.packages.guestbook-jar) pname nativeBuildInputs;
|
||||
version = "0.0.1";
|
||||
src = config.packages.guestbook-jar;
|
||||
buildPhase = ''
|
||||
native-image -H:+ReportExceptionStackTraces -H:+AddAllCharsets --allow-incomplete-classpath --no-fallback --initialize-at-run-time --enable-http --enable-all-security-services --verbose -jar "./${pname}.jar" ./${pname}
|
||||
'';
|
||||
installPhase = ''
|
||||
mkdir -p $out/bin
|
||||
cp ${pname} $out/bin/${pname}
|
||||
'';
|
||||
};
|
||||
packages.default = config.packages.gazesys;
|
||||
};
|
||||
};
|
||||
|
5
gazebot/.gitignore
vendored
5
gazebot/.gitignore
vendored
@ -1,5 +0,0 @@
|
||||
target
|
||||
.env
|
||||
Secrets.toml/target
|
||||
.shuttle*
|
||||
Secrets*.toml
|
3176
gazebot/Cargo.lock
generated
3176
gazebot/Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -1,15 +0,0 @@
|
||||
[package]
|
||||
name = "gazebot"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
tracing = "0.1"
|
||||
tracing-subscriber = "0.3"
|
||||
dotenvy = "0.15.7"
|
||||
serenity = { version = "0.12", default-features = false, features = ["client", "gateway", "rustls_backend", "model"] }
|
||||
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
|
||||
shuttle-serenity = "0.48.0"
|
||||
shuttle-runtime = "0.48.0"
|
||||
reqwest = { version = "0.12", features = ["json"] }
|
||||
scc = "2"
|
@ -1,133 +0,0 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use reqwest::{header::AUTHORIZATION, Url};
|
||||
use scc::HashMap as ConcurrentHashMap;
|
||||
use serenity::{
|
||||
all::ActivityData,
|
||||
async_trait,
|
||||
json::Value as JsonValue,
|
||||
model::{channel::Message, prelude::*},
|
||||
prelude::*,
|
||||
};
|
||||
use shuttle_runtime::SecretStore;
|
||||
|
||||
const ADMIN_USER_ID: u64 = 853064602904166430;
|
||||
|
||||
struct Handler {
|
||||
http: reqwest::Client,
|
||||
secrets: SecretStore,
|
||||
notes: ConcurrentHashMap<MessageId, String>,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl EventHandler for Handler {
|
||||
async fn message(&self, ctx: Context, msg: Message) {
|
||||
if msg.author.id != UserId::new(ADMIN_USER_ID) {
|
||||
return;
|
||||
}
|
||||
|
||||
if msg.content.starts_with("do ") {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut note_content = msg.content.clone();
|
||||
|
||||
const BSKY_TAG: &str = ".nobsky";
|
||||
let no_bsky_posse = note_content.contains(BSKY_TAG);
|
||||
if no_bsky_posse {
|
||||
note_content = note_content.replace(BSKY_TAG, "");
|
||||
}
|
||||
|
||||
let mut note_data = serenity::json::JsonMap::new();
|
||||
note_data.insert(
|
||||
"content".to_string(),
|
||||
JsonValue::String(note_content.trim().to_string()),
|
||||
);
|
||||
note_data.insert("bskyPosse".to_string(), JsonValue::Bool(!no_bsky_posse));
|
||||
// add replyTo if we are replying to a previous message
|
||||
if let Some(reply_msg) = msg.referenced_message.as_deref() {
|
||||
if let Some(reply_note_id) = self
|
||||
.notes
|
||||
.read_async(&reply_msg.id, |_, v| v.to_owned())
|
||||
.await
|
||||
{
|
||||
note_data.insert("replyTo".to_string(), JsonValue::String(reply_note_id));
|
||||
}
|
||||
}
|
||||
// add embed uri
|
||||
if let Some(uri) = note_content
|
||||
.split(&[' ', '(', ')'][..])
|
||||
.find_map(|s| Url::from_str(s).ok())
|
||||
{
|
||||
note_data.insert("embedUri".to_string(), JsonValue::String(uri.to_string()));
|
||||
}
|
||||
let resp = self
|
||||
.http
|
||||
.post("https://gaze.systems/log/create")
|
||||
.header(AUTHORIZATION, self.secrets.get("DISCORD_TOKEN").unwrap())
|
||||
.json(¬e_data)
|
||||
.send()
|
||||
.await
|
||||
.and_then(|resp| resp.error_for_status());
|
||||
|
||||
let resp = match resp {
|
||||
Ok(r) => r,
|
||||
Err(why) => {
|
||||
tracing::error!("could not create note: {why}");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let note_resp = resp.json::<serenity::json::JsonMap>().await.unwrap();
|
||||
let created_note_id = note_resp["noteId"]
|
||||
.as_str()
|
||||
.expect("note id must be a string");
|
||||
tracing::info!("succesfully created note with id {created_note_id}");
|
||||
|
||||
self.notes
|
||||
.upsert_async(msg.id, created_note_id.to_string())
|
||||
.await;
|
||||
|
||||
let mut reply_content =
|
||||
format!("created log at https://gaze.systems/log?id={created_note_id}");
|
||||
let errors = note_resp["errors"].as_array().expect("must be array");
|
||||
if !errors.is_empty() {
|
||||
reply_content.push_str("\n\nerrors:");
|
||||
for error in errors {
|
||||
reply_content.push_str("\n--> ");
|
||||
reply_content.push_str(error.as_str().expect("must be str"));
|
||||
}
|
||||
}
|
||||
|
||||
let _ = msg.reply(ctx, reply_content).await;
|
||||
}
|
||||
|
||||
async fn ready(&self, ctx: Context, ready: Ready) {
|
||||
tracing::info!("{} is connected!", ready.user.name);
|
||||
|
||||
ctx.set_presence(
|
||||
Some(ActivityData::listening("messages")),
|
||||
OnlineStatus::Online,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[shuttle_runtime::main]
|
||||
async fn serenity(
|
||||
#[shuttle_runtime::Secrets] secrets: SecretStore,
|
||||
) -> shuttle_serenity::ShuttleSerenity {
|
||||
let token = secrets.get("DISCORD_TOKEN").unwrap();
|
||||
|
||||
let intents = GatewayIntents::DIRECT_MESSAGES | GatewayIntents::MESSAGE_CONTENT;
|
||||
|
||||
let client = Client::builder(&token, intents)
|
||||
.event_handler(Handler {
|
||||
http: reqwest::Client::new(),
|
||||
secrets,
|
||||
notes: ConcurrentHashMap::new(),
|
||||
})
|
||||
.await
|
||||
.expect("Err creating client");
|
||||
|
||||
Ok(client.into())
|
||||
}
|
@ -1 +0,0 @@
|
||||
{"name":"sbt","version":"1.10.1","bspVersion":"2.1.0-M1","languages":["scala"],"argv":["C:\\Users\\dusk\\scoop\\apps\\graalvm-oracle-jdk\\current/bin/java","-Xms100m","-Xmx100m","-classpath","C:\\Users\\dusk\\AppData\\Local\\Coursier\\cache\\arc\\https\\github.com\\sbt\\sbt\\releases\\download\\v1.10.1\\sbt-1.10.1.zip\\sbt\\bin\\sbt-launch.jar","-Dsbt.script=C:\\Users\\dusk\\AppData\\Local\\Coursier\\data\\bin\\sbt.bat","xsbt.boot.Boot","-bsp"]}
|
@ -1,2 +0,0 @@
|
||||
version = "3.7.15"
|
||||
runner.dialect = scala3
|
@ -1,30 +0,0 @@
|
||||
val Http4sVersion = "0.23.27"
|
||||
val CirceVersion = "0.14.9"
|
||||
val MunitVersion = "1.0.0"
|
||||
val LogbackVersion = "1.5.6"
|
||||
val MunitCatsEffectVersion = "2.0.0"
|
||||
|
||||
lazy val root = (project in file("."))
|
||||
.enablePlugins(GraalVMNativeImagePlugin)
|
||||
.settings(
|
||||
organization := "systems.gaze",
|
||||
name := "guestbook",
|
||||
version := "0.0.1-SNAPSHOT",
|
||||
scalaVersion := "3.4.2",
|
||||
libraryDependencies ++= Seq(
|
||||
"org.http4s" %% "http4s-ember-server" % Http4sVersion,
|
||||
"org.http4s" %% "http4s-circe" % Http4sVersion,
|
||||
"org.http4s" %% "http4s-dsl" % Http4sVersion,
|
||||
"org.scalameta" %% "munit" % MunitVersion % Test,
|
||||
"org.typelevel" %% "munit-cats-effect" % MunitCatsEffectVersion % Test,
|
||||
"ch.qos.logback" % "logback-classic" % LogbackVersion % Runtime,
|
||||
"com.lihaoyi" %% "os-lib" % "0.9.1",
|
||||
"io.circe" %% "circe-core" % CirceVersion,
|
||||
"io.circe" %% "circe-generic" % CirceVersion,
|
||||
"io.circe" %% "circe-parser" % CirceVersion,
|
||||
),
|
||||
assembly / assemblyMergeStrategy := {
|
||||
case "module-info.class" => MergeStrategy.discard
|
||||
case x => (assembly / assemblyMergeStrategy).value.apply(x)
|
||||
}
|
||||
)
|
@ -1 +0,0 @@
|
||||
sbt.version=1.10.1
|
@ -1,8 +0,0 @@
|
||||
// format: off
|
||||
// DO NOT EDIT! This file is auto-generated.
|
||||
|
||||
// This file enables sbt-bloop to create bloop config files.
|
||||
|
||||
addSbtPlugin("ch.epfl.scala" % "sbt-bloop" % "1.6.0")
|
||||
|
||||
// format: on
|
@ -1,4 +0,0 @@
|
||||
addSbtPlugin("org.typelevel" % "sbt-tpolecat" % "0.5.1")
|
||||
addSbtPlugin("io.spray" % "sbt-revolver" % "0.10.0")
|
||||
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "2.2.0")
|
||||
addSbtPlugin("com.github.sbt" % "sbt-native-packager" % "1.10.4")
|
@ -1,8 +0,0 @@
|
||||
// format: off
|
||||
// DO NOT EDIT! This file is auto-generated.
|
||||
|
||||
// This file enables sbt-bloop to create bloop config files.
|
||||
|
||||
addSbtPlugin("ch.epfl.scala" % "sbt-bloop" % "1.6.0")
|
||||
|
||||
// format: on
|
@ -1,8 +0,0 @@
|
||||
// format: off
|
||||
// DO NOT EDIT! This file is auto-generated.
|
||||
|
||||
// This file enables sbt-bloop to create bloop config files.
|
||||
|
||||
addSbtPlugin("ch.epfl.scala" % "sbt-bloop" % "1.6.0")
|
||||
|
||||
// format: on
|
@ -1,16 +0,0 @@
|
||||
<configuration>
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<!-- On Windows machines setting withJansi to true enables ANSI
|
||||
color code interpretation by the Jansi library. This requires
|
||||
org.fusesource.jansi:jansi:1.8 on the class path. Note that
|
||||
Unix-based operating systems such as Linux and Mac OS X
|
||||
support ANSI color codes by default. -->
|
||||
<withJansi>true</withJansi>
|
||||
<encoder>
|
||||
<pattern>[%thread] %highlight(%-5level) %cyan(%logger{15}) - %msg %n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
<root level="INFO">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</root>
|
||||
</configuration>
|
@ -1,57 +0,0 @@
|
||||
package systems.gaze.guestbook
|
||||
|
||||
import cats.Applicative
|
||||
import cats.syntax.all.*
|
||||
import io.circe.Decoder
|
||||
import io.circe.generic.auto._, io.circe.syntax._, io.circe._, io.circe.parser._
|
||||
import os.Path
|
||||
|
||||
trait Guestbook[F[_]]:
|
||||
def read(config: Guestbook.Config, from: Int, count: Int): F[Guestbook.Page]
|
||||
def write(config: Guestbook.Config, entry: Guestbook.Entry): F[Unit]
|
||||
|
||||
object Guestbook:
|
||||
private val logger = org.log4s.getLogger
|
||||
|
||||
final case class Config(
|
||||
val entriesPath: Path,
|
||||
val entryCountPath: Path,
|
||||
)
|
||||
final case class Entry(
|
||||
val author: String,
|
||||
val content: String,
|
||||
val timestamp: Long
|
||||
)
|
||||
final case class Page(
|
||||
val entries: List[Tuple2[Int, Entry]],
|
||||
val hasNext: Boolean,
|
||||
)
|
||||
|
||||
def impl[F[_]: Applicative]: Guestbook[F] = new Guestbook[F]:
|
||||
def entriesSize(config: Config): Int =
|
||||
os.read(config.entryCountPath).toInt
|
||||
def read(config: Config, from: Int, count: Int): F[Page] =
|
||||
val entryCount = entriesSize(config)
|
||||
val entryIds = (1 to entryCount).reverse.drop(from).take(count)
|
||||
// actually get the entries
|
||||
val entries = entryIds
|
||||
.map((no) => // read the entries
|
||||
logger.info(s"reading entry at $no")
|
||||
no -> decode[Entry](os.read(config.entriesPath / no.toString)).getOrElse(
|
||||
Entry(
|
||||
author = "error",
|
||||
content = "woops, this is an error!",
|
||||
timestamp = 0
|
||||
)
|
||||
)
|
||||
)
|
||||
.toList
|
||||
Page(entries, hasNext = entries.last._1 > 1).pure[F]
|
||||
def write(config: Config, entry: Entry): F[Unit] =
|
||||
val entryNo = entriesSize(config) + 1
|
||||
val entryPath = config.entriesPath / entryNo.toString
|
||||
// write entry
|
||||
os.write.over(entryPath, entry.asJson.toString)
|
||||
// update entry count
|
||||
os.write.over(config.entryCountPath, entryNo.toString)
|
||||
().pure[F]
|
@ -1,58 +0,0 @@
|
||||
package systems.gaze.guestbook
|
||||
|
||||
import io.circe.generic.auto._
|
||||
import org.http4s.HttpRoutes
|
||||
import org.http4s.dsl.Http4sDsl
|
||||
import org.http4s.circe.CirceEntityEncoder.circeEntityEncoder
|
||||
import org.http4s.UrlForm
|
||||
import org.http4s.headers.Location
|
||||
import cats.effect.IO
|
||||
import cats.implicits.*
|
||||
import org.http4s.server.middleware.Throttle
|
||||
import scala.concurrent.duration.DurationInt
|
||||
import cats.effect.unsafe.implicits.global
|
||||
import scala.concurrent.duration.FiniteDuration
|
||||
import org.http4s.Uri
|
||||
|
||||
class GuestbookRoutes(
|
||||
var guestbookConfig: Guestbook.Config,
|
||||
var websiteUri: Uri
|
||||
):
|
||||
val dsl = new Http4sDsl[IO] {}
|
||||
import dsl.*
|
||||
|
||||
def throttle(
|
||||
amount: Int,
|
||||
per: FiniteDuration
|
||||
)(routes: HttpRoutes[IO]): HttpRoutes[IO] =
|
||||
Throttle
|
||||
.httpRoutes[IO](amount, per)(routes)
|
||||
.unsafeRunSync()
|
||||
|
||||
def routes(
|
||||
G: Guestbook[IO]
|
||||
): HttpRoutes[IO] =
|
||||
val putEntry = HttpRoutes.of[IO] {
|
||||
case req @ POST -> Root =>
|
||||
for {
|
||||
entry <- req.as[UrlForm].map { form =>
|
||||
val author = form.getFirstOrElse("author", "error")
|
||||
val content = form.getFirstOrElse("content", "error")
|
||||
Guestbook
|
||||
.Entry(author, content, timestamp = System.currentTimeMillis / 1000)
|
||||
}
|
||||
result <- G.write(guestbookConfig, entry)
|
||||
resp <- SeeOther(Location(websiteUri / "guestbook"))
|
||||
} yield resp
|
||||
}
|
||||
object OffsetParam extends QueryParamDecoderMatcher[Int]("offset")
|
||||
object CountParam extends QueryParamDecoderMatcher[Int]("count")
|
||||
val getEntries = HttpRoutes.of[IO] {
|
||||
case GET -> Root :? OffsetParam(offset) +& CountParam(count) =>
|
||||
for {
|
||||
entries <- G.read(guestbookConfig, offset, count)
|
||||
resp <- Ok(entries)
|
||||
} yield resp
|
||||
}
|
||||
throttle(30, 2.seconds)(getEntries)
|
||||
<+> throttle(5, 30.seconds)(putEntry)
|
@ -1,35 +0,0 @@
|
||||
package systems.gaze.guestbook
|
||||
|
||||
import com.comcast.ip4s.*
|
||||
import fs2.io.net.Network
|
||||
import org.http4s.ember.server.EmberServerBuilder
|
||||
import org.http4s.implicits.*
|
||||
import org.http4s.server.middleware.Logger
|
||||
import cats.effect.IO
|
||||
import org.http4s.Uri
|
||||
|
||||
object GuestbookServer:
|
||||
|
||||
def run(
|
||||
guestbookConfig: Guestbook.Config,
|
||||
websiteUri: Uri,
|
||||
): IO[Nothing] = {
|
||||
val guestbookAlg = Guestbook.impl[IO]
|
||||
|
||||
// Combine Service Routes into an HttpApp.
|
||||
// Can also be done via a Router if you
|
||||
// want to extract segments not checked
|
||||
// in the underlying routes.
|
||||
val httpApp =
|
||||
(GuestbookRoutes(guestbookConfig, websiteUri).routes(guestbookAlg)).orNotFound
|
||||
|
||||
// With Middlewares in place
|
||||
val finalHttpApp = Logger.httpApp(true, true)(httpApp)
|
||||
|
||||
EmberServerBuilder
|
||||
.default[IO]
|
||||
.withHost(ipv4"0.0.0.0")
|
||||
.withPort(port"8080")
|
||||
.withHttpApp(finalHttpApp)
|
||||
.build
|
||||
}.useForever
|
@ -1,20 +0,0 @@
|
||||
package systems.gaze.guestbook
|
||||
|
||||
import cats.effect.IOApp
|
||||
import org.http4s.Uri
|
||||
|
||||
object Main extends IOApp.Simple:
|
||||
val websiteUri =
|
||||
Uri
|
||||
.fromString(sys.env("GUESTBOOK_WEBSITE_URI"))
|
||||
.getOrElse(throw new Exception("write better uris lol"))
|
||||
val guestbookConfig = Guestbook.Config(
|
||||
entriesPath = os.pwd / "entries",
|
||||
entryCountPath = os.pwd / "entries_size"
|
||||
)
|
||||
// make the entries path if it doesnt exist
|
||||
os.makeDir.all(guestbookConfig.entriesPath)
|
||||
// make the entry count path if it doesnt exist
|
||||
if !os.exists(guestbookConfig.entryCountPath) then
|
||||
os.write(guestbookConfig.entryCountPath, 0.toString)
|
||||
val run = GuestbookServer.run(guestbookConfig, websiteUri)
|
Loading…
x
Reference in New Issue
Block a user