feat: add redis (#242)
* feat: add refis * feat: add redis package Co-authored-by: Meier Lukas <meierschlumpf@gmail.com> * feat: add example docker compose, add redis connection in package * fix: usage of client after subscribe * feat: add logger for redis * refactor: format files Co-authored-by: Meier Lukas <meierschlumpf@gmail.com> --------- Co-authored-by: Meier Lukas <meierschlumpf@gmail.com>
This commit is contained in:
@@ -25,6 +25,7 @@
|
||||
"@homarr/db": "workspace:^0.1.0",
|
||||
"@homarr/definitions": "workspace:^0.1.0",
|
||||
"@homarr/log": "workspace:^",
|
||||
"@homarr/redis": "workspace:^0.1.0",
|
||||
"@homarr/validation": "workspace:^0.1.0",
|
||||
"@trpc/client": "next",
|
||||
"@trpc/server": "next",
|
||||
|
||||
@@ -5,6 +5,7 @@ import { createSalt, hashPassword } from "@homarr/auth";
|
||||
import type { Database } from "@homarr/db";
|
||||
import { createId, eq, schema } from "@homarr/db";
|
||||
import { users } from "@homarr/db/schema/sqlite";
|
||||
import { exampleChannel } from "@homarr/redis";
|
||||
import { validation, z } from "@homarr/validation";
|
||||
|
||||
import { createTRPCRouter, publicProcedure } from "../trpc";
|
||||
@@ -106,13 +107,14 @@ export const userRouter = createTRPCRouter({
|
||||
})
|
||||
.where(eq(users.id, input.userId));
|
||||
}),
|
||||
setMessage: publicProcedure.input(z.string()).mutation(async ({ input }) => {
|
||||
await exampleChannel.publish({ message: input });
|
||||
}),
|
||||
test: publicProcedure.subscription(() => {
|
||||
return observable<number>((emit) => {
|
||||
let counter = 0;
|
||||
setInterval(() => {
|
||||
counter = counter + 1;
|
||||
emit.next(counter);
|
||||
}, 1000);
|
||||
return observable<{ message: string }>((emit) => {
|
||||
exampleChannel.subscribe((message) => {
|
||||
emit.next(message);
|
||||
});
|
||||
});
|
||||
}),
|
||||
});
|
||||
|
||||
1
packages/redis/index.ts
Normal file
1
packages/redis/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from "./src";
|
||||
40
packages/redis/package.json
Normal file
40
packages/redis/package.json
Normal file
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"name": "@homarr/redis",
|
||||
"private": true,
|
||||
"version": "0.1.0",
|
||||
"exports": {
|
||||
".": "./index.ts"
|
||||
},
|
||||
"typesVersions": {
|
||||
"*": {
|
||||
"*": [
|
||||
"src/*"
|
||||
]
|
||||
}
|
||||
},
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"clean": "rm -rf .turbo node_modules",
|
||||
"lint": "eslint .",
|
||||
"format": "prettier --check . --ignore-path ../../.gitignore",
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"ioredis": "5.3.2",
|
||||
"@homarr/log": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||
"@homarr/prettier-config": "workspace:^0.1.0",
|
||||
"@homarr/tsconfig": "workspace:^0.1.0",
|
||||
"eslint": "^8.57.0",
|
||||
"typescript": "^5.4.3"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": [
|
||||
"@homarr/eslint-config/base"
|
||||
]
|
||||
},
|
||||
"prettier": "@homarr/prettier-config"
|
||||
}
|
||||
39
packages/redis/src/index.ts
Normal file
39
packages/redis/src/index.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import { Redis } from "ioredis";
|
||||
import superjson from "superjson";
|
||||
|
||||
import { logger } from "@homarr/log";
|
||||
|
||||
const subscriber = new Redis();
|
||||
const publisher = new Redis();
|
||||
const lastDataClient = new Redis();
|
||||
|
||||
const createChannel = <TData>(name: string) => {
|
||||
return {
|
||||
subscribe: (callback: (data: TData) => void) => {
|
||||
void lastDataClient.get(`last-${name}`).then((data) => {
|
||||
if (data) {
|
||||
callback(superjson.parse(data));
|
||||
}
|
||||
});
|
||||
void subscriber.subscribe(name, (err) => {
|
||||
if (!err) {
|
||||
return;
|
||||
}
|
||||
logger.error(
|
||||
`Error with channel '${name}': ${err.name} (${err.message})`,
|
||||
);
|
||||
});
|
||||
subscriber.on("message", (channel, message) => {
|
||||
if (channel !== name) return;
|
||||
|
||||
callback(superjson.parse(message));
|
||||
});
|
||||
},
|
||||
publish: async (data: TData) => {
|
||||
await lastDataClient.set(`last-${name}`, superjson.stringify(data));
|
||||
await publisher.publish(name, superjson.stringify(data));
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export const exampleChannel = createChannel<{ message: string }>("example");
|
||||
8
packages/redis/tsconfig.json
Normal file
8
packages/redis/tsconfig.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"extends": "@homarr/tsconfig/base.json",
|
||||
"compilerOptions": {
|
||||
"tsBuildInfoFile": "node_modules/.cache/tsbuildinfo.json"
|
||||
},
|
||||
"include": ["*.ts", "src"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
Reference in New Issue
Block a user