feat: init
This commit is contained in:
		
						commit
						96ca2076ed
					
				
							
								
								
									
										34
									
								
								.cargo/config.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								.cargo/config.toml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,34 @@
 | 
				
			|||||||
 | 
					[alias]
 | 
				
			||||||
 | 
					recorder = "run -p recorder --bin recorder_cli -- --environment recorder.development"
 | 
				
			||||||
 | 
					recorder-playground = "run -p recorder --example playground -- --environment recorder.development"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[build]
 | 
				
			||||||
 | 
					rustflags = ["-Zthreads=8"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[target.x86_64-unknown-linux-gnu]
 | 
				
			||||||
 | 
					linker = "clang"
 | 
				
			||||||
 | 
					rustflags = ["-Zthreads=8", "-Clink-arg=-fuse-ld=lld", "-Zshare-generics=y"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[target.x86_64-pc-windows-msvc]
 | 
				
			||||||
 | 
					linker = "rust-lld.exe"
 | 
				
			||||||
 | 
					rustflags = ["-Zthreads=8", "-Zshare-generics=n"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# NOTE: you must install [Mach-O LLD Port](https://lld.llvm.org/MachO/index.html) on mac. you can easily do this by installing llvm which includes lld with the "brew" package manager:
 | 
				
			||||||
 | 
					# `brew install llvm`
 | 
				
			||||||
 | 
					#[target.x86_64-apple-darwin]
 | 
				
			||||||
 | 
					#rustflags = [
 | 
				
			||||||
 | 
					#    "-Zthreads=8",
 | 
				
			||||||
 | 
					#    "-C",
 | 
				
			||||||
 | 
					#    "link-arg=-fuse-ld=/usr/local/opt/llvm/bin/ld64.lld",
 | 
				
			||||||
 | 
					#    "-Zshare-generics=y",
 | 
				
			||||||
 | 
					#]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# NOTE: you must install [Mach-O LLD Port](https://lld.llvm.org/MachO/index.html) on mac. you can easily do this by installing llvm which includes lld with the "brew" package manager:
 | 
				
			||||||
 | 
					# `brew install llvm`
 | 
				
			||||||
 | 
					#[target.aarch64-apple-darwin]
 | 
				
			||||||
 | 
					#rustflags = [
 | 
				
			||||||
 | 
					#    "-Zthreads=8",
 | 
				
			||||||
 | 
					#    "-C",
 | 
				
			||||||
 | 
					#    "link-arg=-fuse-ld=/opt/homebrew/opt/llvm/bin/ld64.lld",
 | 
				
			||||||
 | 
					#    "-Zshare-generics=y",
 | 
				
			||||||
 | 
					#]
 | 
				
			||||||
							
								
								
									
										222
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										222
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,222 @@
 | 
				
			|||||||
 | 
					### VisualStudioCode template
 | 
				
			||||||
 | 
					.vscode/*
 | 
				
			||||||
 | 
					!.vscode/settings.json
 | 
				
			||||||
 | 
					!.vscode/tasks.json
 | 
				
			||||||
 | 
					!.vscode/launch.json
 | 
				
			||||||
 | 
					!.vscode/extensions.json
 | 
				
			||||||
 | 
					*.code-workspace
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Local History for Visual Studio Code
 | 
				
			||||||
 | 
					.history/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### JetBrains template
 | 
				
			||||||
 | 
					# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
 | 
				
			||||||
 | 
					# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# User-specific stuff
 | 
				
			||||||
 | 
					.idea/**/workspace.xml
 | 
				
			||||||
 | 
					.idea/**/tasks.xml
 | 
				
			||||||
 | 
					.idea/**/usage.statistics.xml
 | 
				
			||||||
 | 
					.idea/**/dictionaries
 | 
				
			||||||
 | 
					.idea/**/shelf
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Generated files
 | 
				
			||||||
 | 
					.idea/**/contentModel.xml
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Sensitive or high-churn files
 | 
				
			||||||
 | 
					.idea/**/dataSources/
 | 
				
			||||||
 | 
					.idea/**/dataSources.ids
 | 
				
			||||||
 | 
					.idea/**/dataSources.local.xml
 | 
				
			||||||
 | 
					.idea/**/sqlDataSources.xml
 | 
				
			||||||
 | 
					.idea/**/dynamic.xml
 | 
				
			||||||
 | 
					.idea/**/uiDesigner.xml
 | 
				
			||||||
 | 
					.idea/**/dbnavigator.xml
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Gradle
 | 
				
			||||||
 | 
					.idea/**/gradle.xml
 | 
				
			||||||
 | 
					.idea/**/libraries
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Gradle and Maven with auto-import
 | 
				
			||||||
 | 
					# When using Gradle or Maven with auto-import, you should exclude module files,
 | 
				
			||||||
 | 
					# since they will be recreated, and may cause churn.  Uncomment if using
 | 
				
			||||||
 | 
					# auto-import.
 | 
				
			||||||
 | 
					# .idea/artifacts
 | 
				
			||||||
 | 
					# .idea/compiler.xml
 | 
				
			||||||
 | 
					# .idea/jarRepositories.xml
 | 
				
			||||||
 | 
					# .idea/modules.xml
 | 
				
			||||||
 | 
					# .idea/*.iml
 | 
				
			||||||
 | 
					# .idea/modules
 | 
				
			||||||
 | 
					# *.iml
 | 
				
			||||||
 | 
					# *.ipr
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# CMake
 | 
				
			||||||
 | 
					cmake-build-*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Mongo Explorer plugin
 | 
				
			||||||
 | 
					.idea/**/mongoSettings.xml
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# File-based project format
 | 
				
			||||||
 | 
					*.iws
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# IntelliJ
 | 
				
			||||||
 | 
					out/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# mpeltonen/sbt-idea plugin
 | 
				
			||||||
 | 
					.idea_modules/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# JIRA plugin
 | 
				
			||||||
 | 
					atlassian-ide-plugin.xml
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Cursive Clojure plugin
 | 
				
			||||||
 | 
					.idea/replstate.xml
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Crashlytics plugin (for Android Studio and IntelliJ)
 | 
				
			||||||
 | 
					com_crashlytics_export_strings.xml
 | 
				
			||||||
 | 
					crashlytics.properties
 | 
				
			||||||
 | 
					crashlytics-build.properties
 | 
				
			||||||
 | 
					fabric.properties
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Editor-based Rest Client
 | 
				
			||||||
 | 
					.idea/httpRequests
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Android studio 3.1+ serialized cache file
 | 
				
			||||||
 | 
					.idea/caches/build_file_checksums.ser
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.idea
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Node template
 | 
				
			||||||
 | 
					# Logs
 | 
				
			||||||
 | 
					logs
 | 
				
			||||||
 | 
					*.log
 | 
				
			||||||
 | 
					npm-debug.log*
 | 
				
			||||||
 | 
					yarn-debug.log*
 | 
				
			||||||
 | 
					yarn-error.log*
 | 
				
			||||||
 | 
					lerna-debug.log*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Diagnostic reports (https://nodejs.org/api/report.html)
 | 
				
			||||||
 | 
					report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Runtime data
 | 
				
			||||||
 | 
					pids
 | 
				
			||||||
 | 
					*.pid
 | 
				
			||||||
 | 
					*.seed
 | 
				
			||||||
 | 
					*.pid.lock
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Directory for instrumented libs generated by jscoverage/JSCover
 | 
				
			||||||
 | 
					lib-cov
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Coverage directory used by tools like istanbul
 | 
				
			||||||
 | 
					coverage
 | 
				
			||||||
 | 
					*.lcov
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# nyc tests coverage
 | 
				
			||||||
 | 
					.nyc_output
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
 | 
				
			||||||
 | 
					.grunt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Bower dependency directory (https://bower.io/)
 | 
				
			||||||
 | 
					bower_components
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# node-waf configuration
 | 
				
			||||||
 | 
					.lock-wscript
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Compiled binary addons (https://nodejs.org/api/addons.html)
 | 
				
			||||||
 | 
					build/Release
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Dependency directories
 | 
				
			||||||
 | 
					node_modules/
 | 
				
			||||||
 | 
					jspm_packages/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Snowpack dependency directory (https://snowpack.dev/)
 | 
				
			||||||
 | 
					web_modules/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# TypeScript cache
 | 
				
			||||||
 | 
					*.tsbuildinfo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Optional npm cache directory
 | 
				
			||||||
 | 
					.npm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Optional eslint cache
 | 
				
			||||||
 | 
					.eslintcache
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Microbundle cache
 | 
				
			||||||
 | 
					.rpt2_cache/
 | 
				
			||||||
 | 
					.rts2_cache_cjs/
 | 
				
			||||||
 | 
					.rts2_cache_es/
 | 
				
			||||||
 | 
					.rts2_cache_umd/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Optional REPL history
 | 
				
			||||||
 | 
					.node_repl_history
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Output of 'npm pack'
 | 
				
			||||||
 | 
					*.tgz
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Yarn Integrity file
 | 
				
			||||||
 | 
					.yarn-integrity
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# dotenv environment variables file
 | 
				
			||||||
 | 
					.env
 | 
				
			||||||
 | 
					.env.test
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# parcel-bundler cache (https://parceljs.org/)
 | 
				
			||||||
 | 
					.cache
 | 
				
			||||||
 | 
					.parcel-cache
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Next.js build output
 | 
				
			||||||
 | 
					.next
 | 
				
			||||||
 | 
					out
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Nuxt.js build / generate output
 | 
				
			||||||
 | 
					.nuxt
 | 
				
			||||||
 | 
					dist
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Gatsby files
 | 
				
			||||||
 | 
					.cache/
 | 
				
			||||||
 | 
					# Comment in the public line in if your project uses Gatsby and not Next.js
 | 
				
			||||||
 | 
					# https://nextjs.org/blog/next-9-1#public-directory-support
 | 
				
			||||||
 | 
					# public
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# vuepress build output
 | 
				
			||||||
 | 
					.vuepress/dist
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Serverless directories
 | 
				
			||||||
 | 
					.serverless/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# FuseBox cache
 | 
				
			||||||
 | 
					.fusebox/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# DynamoDB Local files
 | 
				
			||||||
 | 
					.dynamodb/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# TernJS port file
 | 
				
			||||||
 | 
					.tern-port
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Stores VSCode versions used for testing VSCode extensions
 | 
				
			||||||
 | 
					.vscode-test
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# yarn v2
 | 
				
			||||||
 | 
					.yarn/cache
 | 
				
			||||||
 | 
					.yarn/unplugged
 | 
				
			||||||
 | 
					.yarn/build-state.yml
 | 
				
			||||||
 | 
					.yarn/install-state.gz
 | 
				
			||||||
 | 
					.pnp.*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					index.js
 | 
				
			||||||
 | 
					index.js.map
 | 
				
			||||||
 | 
					index.d.ts
 | 
				
			||||||
 | 
					index.d.ts.map
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**/dist
 | 
				
			||||||
 | 
					**/preview_dist
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Added by cargo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/target
 | 
				
			||||||
 | 
					/examples/*
 | 
				
			||||||
 | 
					!/examples/.gitkeep
 | 
				
			||||||
 | 
					/.env
 | 
				
			||||||
 | 
					/.env.bk
 | 
				
			||||||
 | 
					/.angular
 | 
				
			||||||
 | 
					/*.session.sql
 | 
				
			||||||
							
								
								
									
										5205
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										5205
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										3
									
								
								Cargo.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								Cargo.toml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					[workspace]
 | 
				
			||||||
 | 
					members = ["crates/recorder"]
 | 
				
			||||||
 | 
					resolver = "2"
 | 
				
			||||||
							
								
								
									
										21
									
								
								LICENSE
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								LICENSE
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,21 @@
 | 
				
			|||||||
 | 
					MIT License
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Copyright (c) Zhou Yeheng
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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.
 | 
				
			||||||
							
								
								
									
										5
									
								
								apps/proxy/.whistle/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								apps/proxy/.whistle/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					**/.backup
 | 
				
			||||||
 | 
					**/.recycle_bin
 | 
				
			||||||
 | 
					**/.clientid
 | 
				
			||||||
 | 
					/properties/*
 | 
				
			||||||
 | 
					!/properties/properties
 | 
				
			||||||
							
								
								
									
										1
									
								
								apps/proxy/.whistle/properties/properties
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								apps/proxy/.whistle/properties/properties
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					{"filesOrder":["latestVersion"],"Custom1":"Custom1","Custom2":"Custom2","allowMultipleChoice":true}
 | 
				
			||||||
							
								
								
									
										2
									
								
								apps/proxy/.whistle/rules/files/0.webui
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								apps/proxy/.whistle/rules/files/0.webui
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,2 @@
 | 
				
			|||||||
 | 
					^https://webui.konobangu.com/*** http://127.0.0.1:3000/$1
 | 
				
			||||||
 | 
					^wss://webui.konobangu.com/*** ws://127.0.0.1:3000/$1
 | 
				
			||||||
							
								
								
									
										1
									
								
								apps/proxy/.whistle/rules/files/2.recorder
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								apps/proxy/.whistle/rules/files/2.recorder
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					^https://recorder.konobangu.com/*** http://127.0.0.1:7600/$1
 | 
				
			||||||
							
								
								
									
										1
									
								
								apps/proxy/.whistle/rules/properties
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								apps/proxy/.whistle/rules/properties
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					{"filesOrder":["webui","recorder"],"selectedList":["webui","recorder"],"disabledDefalutRules":true}
 | 
				
			||||||
							
								
								
									
										0
									
								
								apps/proxy/.whistle/values/properties
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								apps/proxy/.whistle/values/properties
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										13
									
								
								apps/proxy/package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								apps/proxy/package.json
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,13 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "name": "proxy",
 | 
				
			||||||
 | 
					  "version": "0.1.0",
 | 
				
			||||||
 | 
					  "private": true,
 | 
				
			||||||
 | 
					  "scripts": {
 | 
				
			||||||
 | 
					    "start": "whistle run -p 8899 -t 30000 -M \"keepXFF|prod|capture\" -D . --no-global-plugins"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "keywords": [],
 | 
				
			||||||
 | 
					  "license": "MIT",
 | 
				
			||||||
 | 
					  "devDependencies": {
 | 
				
			||||||
 | 
					    "whistle": "^2.9.61"
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										6
									
								
								apps/webui/.eslintrc.mjs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								apps/webui/.eslintrc.mjs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					export default {
 | 
				
			||||||
 | 
					  "extends": "next/core-web-vitals",
 | 
				
			||||||
 | 
					  "rules": {
 | 
				
			||||||
 | 
					    "@typescript-eslint/consistent-type-imports": "error"
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										36
									
								
								apps/webui/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								apps/webui/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,36 @@
 | 
				
			|||||||
 | 
					# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# dependencies
 | 
				
			||||||
 | 
					/node_modules
 | 
				
			||||||
 | 
					/.pnp
 | 
				
			||||||
 | 
					.pnp.js
 | 
				
			||||||
 | 
					.yarn/install-state.gz
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# testing
 | 
				
			||||||
 | 
					/coverage
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# next.js
 | 
				
			||||||
 | 
					/.next/
 | 
				
			||||||
 | 
					/out/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# production
 | 
				
			||||||
 | 
					/build
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# misc
 | 
				
			||||||
 | 
					.DS_Store
 | 
				
			||||||
 | 
					*.pem
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# debug
 | 
				
			||||||
 | 
					npm-debug.log*
 | 
				
			||||||
 | 
					yarn-debug.log*
 | 
				
			||||||
 | 
					yarn-error.log*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# local env files
 | 
				
			||||||
 | 
					.env*.local
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# vercel
 | 
				
			||||||
 | 
					.vercel
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# typescript
 | 
				
			||||||
 | 
					*.tsbuildinfo
 | 
				
			||||||
 | 
					next-env.d.ts
 | 
				
			||||||
							
								
								
									
										36
									
								
								apps/webui/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								apps/webui/README.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,36 @@
 | 
				
			|||||||
 | 
					This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Getting Started
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					First, run the development server:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					npm run dev
 | 
				
			||||||
 | 
					# or
 | 
				
			||||||
 | 
					yarn dev
 | 
				
			||||||
 | 
					# or
 | 
				
			||||||
 | 
					pnpm dev
 | 
				
			||||||
 | 
					# or
 | 
				
			||||||
 | 
					bun dev
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Learn More
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					To learn more about Next.js, take a look at the following resources:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
 | 
				
			||||||
 | 
					- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Deploy on Vercel
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								apps/webui/app/favicon.ico
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								apps/webui/app/favicon.ico
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 25 KiB  | 
							
								
								
									
										76
									
								
								apps/webui/app/globals.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								apps/webui/app/globals.css
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,76 @@
 | 
				
			|||||||
 | 
					@tailwind base;
 | 
				
			||||||
 | 
					@tailwind components;
 | 
				
			||||||
 | 
					@tailwind utilities;
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					@layer base {
 | 
				
			||||||
 | 
					  :root {
 | 
				
			||||||
 | 
					    --background: 0 0% 100%;
 | 
				
			||||||
 | 
					    --foreground: 0 0% 3.9%;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    --card: 0 0% 100%;
 | 
				
			||||||
 | 
					    --card-foreground: 0 0% 3.9%;
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					    --popover: 0 0% 100%;
 | 
				
			||||||
 | 
					    --popover-foreground: 0 0% 3.9%;
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					    --primary: 0 0% 9%;
 | 
				
			||||||
 | 
					    --primary-foreground: 0 0% 98%;
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					    --secondary: 0 0% 96.1%;
 | 
				
			||||||
 | 
					    --secondary-foreground: 0 0% 9%;
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					    --muted: 0 0% 96.1%;
 | 
				
			||||||
 | 
					    --muted-foreground: 0 0% 45.1%;
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					    --accent: 0 0% 96.1%;
 | 
				
			||||||
 | 
					    --accent-foreground: 0 0% 9%;
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					    --destructive: 0 84.2% 60.2%;
 | 
				
			||||||
 | 
					    --destructive-foreground: 0 0% 98%;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    --border: 0 0% 89.8%;
 | 
				
			||||||
 | 
					    --input: 0 0% 89.8%;
 | 
				
			||||||
 | 
					    --ring: 0 0% 3.9%;
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					    --radius: 0.5rem;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					  .dark {
 | 
				
			||||||
 | 
					    --background: 0 0% 3.9%;
 | 
				
			||||||
 | 
					    --foreground: 0 0% 98%;
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					    --card: 0 0% 3.9%;
 | 
				
			||||||
 | 
					    --card-foreground: 0 0% 98%;
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					    --popover: 0 0% 3.9%;
 | 
				
			||||||
 | 
					    --popover-foreground: 0 0% 98%;
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					    --primary: 0 0% 98%;
 | 
				
			||||||
 | 
					    --primary-foreground: 0 0% 9%;
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					    --secondary: 0 0% 14.9%;
 | 
				
			||||||
 | 
					    --secondary-foreground: 0 0% 98%;
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					    --muted: 0 0% 14.9%;
 | 
				
			||||||
 | 
					    --muted-foreground: 0 0% 63.9%;
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					    --accent: 0 0% 14.9%;
 | 
				
			||||||
 | 
					    --accent-foreground: 0 0% 98%;
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					    --destructive: 0 62.8% 30.6%;
 | 
				
			||||||
 | 
					    --destructive-foreground: 0 0% 98%;
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					    --border: 0 0% 14.9%;
 | 
				
			||||||
 | 
					    --input: 0 0% 14.9%;
 | 
				
			||||||
 | 
					    --ring: 0 0% 83.1%;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					@layer base {
 | 
				
			||||||
 | 
					  * {
 | 
				
			||||||
 | 
					    @apply border-border;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  body {
 | 
				
			||||||
 | 
					    @apply bg-background text-foreground;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										22
									
								
								apps/webui/app/layout.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								apps/webui/app/layout.tsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,22 @@
 | 
				
			|||||||
 | 
					import type { Metadata } from "next";
 | 
				
			||||||
 | 
					import { Inter } from "next/font/google";
 | 
				
			||||||
 | 
					import "./globals.css";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const inter = Inter({ subsets: ["latin"] });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const metadata: Metadata = {
 | 
				
			||||||
 | 
					  title: "Create Next App",
 | 
				
			||||||
 | 
					  description: "Generated by create next app",
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default function RootLayout({
 | 
				
			||||||
 | 
					  children,
 | 
				
			||||||
 | 
					}: Readonly<{
 | 
				
			||||||
 | 
					  children: React.ReactNode;
 | 
				
			||||||
 | 
					}>) {
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <html lang="en">
 | 
				
			||||||
 | 
					      <body className={inter.className}>{children}</body>
 | 
				
			||||||
 | 
					    </html>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										113
									
								
								apps/webui/app/page.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								apps/webui/app/page.tsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,113 @@
 | 
				
			|||||||
 | 
					import Image from "next/image";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default function Home() {
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <main className="flex min-h-screen flex-col items-center justify-between p-24">
 | 
				
			||||||
 | 
					      <div className="z-10 max-w-5xl w-full items-center justify-between font-mono text-sm lg:flex">
 | 
				
			||||||
 | 
					        <p className="fixed left-0 top-0 flex w-full justify-center border-b border-gray-300 bg-gradient-to-b from-zinc-200 pb-6 pt-8 backdrop-blur-2xl dark:border-neutral-800 dark:bg-zinc-800/30 dark:from-inherit lg:static lg:w-auto  lg:rounded-xl lg:border lg:bg-gray-200 lg:p-4 lg:dark:bg-zinc-800/30">
 | 
				
			||||||
 | 
					          Get started by editing 
 | 
				
			||||||
 | 
					          <code className="font-mono font-bold">app/page.tsx</code>
 | 
				
			||||||
 | 
					        </p>
 | 
				
			||||||
 | 
					        <div className="fixed bottom-0 left-0 flex h-48 w-full items-end justify-center bg-gradient-to-t from-white via-white dark:from-black dark:via-black lg:static lg:h-auto lg:w-auto lg:bg-none">
 | 
				
			||||||
 | 
					          <a
 | 
				
			||||||
 | 
					            className="pointer-events-none flex place-items-center gap-2 p-8 lg:pointer-events-auto lg:p-0"
 | 
				
			||||||
 | 
					            href="https://vercel.com?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
 | 
				
			||||||
 | 
					            target="_blank"
 | 
				
			||||||
 | 
					            rel="noopener noreferrer"
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            By{" "}
 | 
				
			||||||
 | 
					            <Image
 | 
				
			||||||
 | 
					              src="/vercel.svg"
 | 
				
			||||||
 | 
					              alt="Vercel Logo"
 | 
				
			||||||
 | 
					              className="dark:invert"
 | 
				
			||||||
 | 
					              width={100}
 | 
				
			||||||
 | 
					              height={24}
 | 
				
			||||||
 | 
					              priority
 | 
				
			||||||
 | 
					            />
 | 
				
			||||||
 | 
					          </a>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      <div className="relative flex place-items-center before:absolute before:h-[300px] before:w-full sm:before:w-[480px] before:-translate-x-1/2 before:rounded-full before:bg-gradient-radial before:from-white before:to-transparent before:blur-2xl before:content-[''] after:absolute after:-z-20 after:h-[180px] after:w-full sm:after:w-[240px] after:translate-x-1/3 after:bg-gradient-conic after:from-sky-200 after:via-blue-200 after:blur-2xl after:content-[''] before:dark:bg-gradient-to-br before:dark:from-transparent before:dark:to-blue-700 before:dark:opacity-10 after:dark:from-sky-900 after:dark:via-[#0141ff] after:dark:opacity-40 before:lg:h-[360px] z-[-1]">
 | 
				
			||||||
 | 
					        <Image
 | 
				
			||||||
 | 
					          className="relative dark:drop-shadow-[0_0_0.3rem_#ffffff70] dark:invert"
 | 
				
			||||||
 | 
					          src="/next.svg"
 | 
				
			||||||
 | 
					          alt="Next.js Logo"
 | 
				
			||||||
 | 
					          width={180}
 | 
				
			||||||
 | 
					          height={37}
 | 
				
			||||||
 | 
					          priority
 | 
				
			||||||
 | 
					        />
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      <div className="mb-32 grid text-center lg:max-w-5xl lg:w-full lg:mb-0 lg:grid-cols-4 lg:text-left">
 | 
				
			||||||
 | 
					        <a
 | 
				
			||||||
 | 
					          href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
 | 
				
			||||||
 | 
					          className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
 | 
				
			||||||
 | 
					          target="_blank"
 | 
				
			||||||
 | 
					          rel="noopener noreferrer"
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          <h2 className={`mb-3 text-2xl font-semibold`}>
 | 
				
			||||||
 | 
					            Docs{" "}
 | 
				
			||||||
 | 
					            <span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
 | 
				
			||||||
 | 
					              ->
 | 
				
			||||||
 | 
					            </span>
 | 
				
			||||||
 | 
					          </h2>
 | 
				
			||||||
 | 
					          <p className={`m-0 max-w-[30ch] text-sm opacity-50`}>
 | 
				
			||||||
 | 
					            Find in-depth information about Next.js features and API.
 | 
				
			||||||
 | 
					          </p>
 | 
				
			||||||
 | 
					        </a>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <a
 | 
				
			||||||
 | 
					          href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
 | 
				
			||||||
 | 
					          className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
 | 
				
			||||||
 | 
					          target="_blank"
 | 
				
			||||||
 | 
					          rel="noopener noreferrer"
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          <h2 className={`mb-3 text-2xl font-semibold`}>
 | 
				
			||||||
 | 
					            Learn{" "}
 | 
				
			||||||
 | 
					            <span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
 | 
				
			||||||
 | 
					              ->
 | 
				
			||||||
 | 
					            </span>
 | 
				
			||||||
 | 
					          </h2>
 | 
				
			||||||
 | 
					          <p className={`m-0 max-w-[30ch] text-sm opacity-50`}>
 | 
				
			||||||
 | 
					            Learn about Next.js in an interactive course with quizzes!
 | 
				
			||||||
 | 
					          </p>
 | 
				
			||||||
 | 
					        </a>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <a
 | 
				
			||||||
 | 
					          href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
 | 
				
			||||||
 | 
					          className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
 | 
				
			||||||
 | 
					          target="_blank"
 | 
				
			||||||
 | 
					          rel="noopener noreferrer"
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          <h2 className={`mb-3 text-2xl font-semibold`}>
 | 
				
			||||||
 | 
					            Templates{" "}
 | 
				
			||||||
 | 
					            <span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
 | 
				
			||||||
 | 
					              ->
 | 
				
			||||||
 | 
					            </span>
 | 
				
			||||||
 | 
					          </h2>
 | 
				
			||||||
 | 
					          <p className={`m-0 max-w-[30ch] text-sm opacity-50`}>
 | 
				
			||||||
 | 
					            Explore starter templates for Next.js.
 | 
				
			||||||
 | 
					          </p>
 | 
				
			||||||
 | 
					        </a>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <a
 | 
				
			||||||
 | 
					          href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
 | 
				
			||||||
 | 
					          className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
 | 
				
			||||||
 | 
					          target="_blank"
 | 
				
			||||||
 | 
					          rel="noopener noreferrer"
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          <h2 className={`mb-3 text-2xl font-semibold`}>
 | 
				
			||||||
 | 
					            Deploy{" "}
 | 
				
			||||||
 | 
					            <span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
 | 
				
			||||||
 | 
					              ->
 | 
				
			||||||
 | 
					            </span>
 | 
				
			||||||
 | 
					          </h2>
 | 
				
			||||||
 | 
					          <p className={`m-0 max-w-[30ch] text-sm opacity-50 text-balance`}>
 | 
				
			||||||
 | 
					            Instantly deploy your Next.js site to a shareable URL with Vercel.
 | 
				
			||||||
 | 
					          </p>
 | 
				
			||||||
 | 
					        </a>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    </main>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										17
									
								
								apps/webui/components.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								apps/webui/components.json
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,17 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "$schema": "https://ui.shadcn.com/schema.json",
 | 
				
			||||||
 | 
					  "style": "new-york",
 | 
				
			||||||
 | 
					  "rsc": true,
 | 
				
			||||||
 | 
					  "tsx": true,
 | 
				
			||||||
 | 
					  "tailwind": {
 | 
				
			||||||
 | 
					    "config": "tailwind.config.ts",
 | 
				
			||||||
 | 
					    "css": "app/globals.css",
 | 
				
			||||||
 | 
					    "baseColor": "neutral",
 | 
				
			||||||
 | 
					    "cssVariables": true,
 | 
				
			||||||
 | 
					    "prefix": ""
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "aliases": {
 | 
				
			||||||
 | 
					    "components": "@/components",
 | 
				
			||||||
 | 
					    "utils": "@/lib/utils"
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										6
									
								
								apps/webui/lib/utils.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								apps/webui/lib/utils.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					import { type ClassValue, clsx } from "clsx"
 | 
				
			||||||
 | 
					import { twMerge } from "tailwind-merge"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function cn(...inputs: ClassValue[]) {
 | 
				
			||||||
 | 
					  return twMerge(clsx(inputs))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										7
									
								
								apps/webui/next.config.mjs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								apps/webui/next.config.mjs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @type { import("next").NextConfig }
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					const nextConfig = {
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default nextConfig;
 | 
				
			||||||
							
								
								
									
										37
									
								
								apps/webui/package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								apps/webui/package.json
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,37 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "name": "webui",
 | 
				
			||||||
 | 
					  "version": "0.1.0",
 | 
				
			||||||
 | 
					  "private": true,
 | 
				
			||||||
 | 
					  "scripts": {
 | 
				
			||||||
 | 
					    "dev": "next dev",
 | 
				
			||||||
 | 
					    "build": "next build",
 | 
				
			||||||
 | 
					    "start": "next start",
 | 
				
			||||||
 | 
					    "lint": "next lint"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "dependencies": {
 | 
				
			||||||
 | 
					    "@radix-ui/react-icons": "^1.3.0",
 | 
				
			||||||
 | 
					    "class-variance-authority": "^0.7.0",
 | 
				
			||||||
 | 
					    "clsx": "^2.1.0",
 | 
				
			||||||
 | 
					    "i18next": "^23.10.0",
 | 
				
			||||||
 | 
					    "next": "14.1.0",
 | 
				
			||||||
 | 
					    "next-i18next": "^15.2.0",
 | 
				
			||||||
 | 
					    "react": "^18",
 | 
				
			||||||
 | 
					    "react-dom": "^18",
 | 
				
			||||||
 | 
					    "react-i18next": "^14.0.5",
 | 
				
			||||||
 | 
					    "tailwind-merge": "^2.2.1",
 | 
				
			||||||
 | 
					    "tailwindcss-animate": "^1.0.7"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "devDependencies": {
 | 
				
			||||||
 | 
					    "@types/node": "^20",
 | 
				
			||||||
 | 
					    "@types/react": "^18",
 | 
				
			||||||
 | 
					    "@types/react-dom": "^18",
 | 
				
			||||||
 | 
					    "@typescript-eslint/eslint-plugin": "^7.0.2",
 | 
				
			||||||
 | 
					    "autoprefixer": "^10.0.1",
 | 
				
			||||||
 | 
					    "eslint": "^8",
 | 
				
			||||||
 | 
					    "eslint-config-next": "14.1.0",
 | 
				
			||||||
 | 
					    "grasslands": "^0.1.3",
 | 
				
			||||||
 | 
					    "postcss": "^8",
 | 
				
			||||||
 | 
					    "tailwindcss": "^3.3.0",
 | 
				
			||||||
 | 
					    "typescript": "^5"
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										6
									
								
								apps/webui/postcss.config.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								apps/webui/postcss.config.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					module.exports = {
 | 
				
			||||||
 | 
					  plugins: {
 | 
				
			||||||
 | 
					    tailwindcss: {},
 | 
				
			||||||
 | 
					    autoprefixer: {},
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										1
									
								
								apps/webui/public/next.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								apps/webui/public/next.svg
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg>
 | 
				
			||||||
| 
		 After Width: | Height: | Size: 1.3 KiB  | 
							
								
								
									
										1
									
								
								apps/webui/public/vercel.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								apps/webui/public/vercel.svg
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 283 64"><path fill="black" d="M141 16c-11 0-19 7-19 18s9 18 20 18c7 0 13-3 16-7l-7-5c-2 3-6 4-9 4-5 0-9-3-10-7h28v-3c0-11-8-18-19-18zm-9 15c1-4 4-7 9-7s8 3 9 7h-18zm117-15c-11 0-19 7-19 18s9 18 20 18c6 0 12-3 16-7l-8-5c-2 3-5 4-8 4-5 0-9-3-11-7h28l1-3c0-11-8-18-19-18zm-10 15c2-4 5-7 10-7s8 3 9 7h-19zm-39 3c0 6 4 10 10 10 4 0 7-2 9-5l8 5c-3 5-9 8-17 8-11 0-19-7-19-18s8-18 19-18c8 0 14 3 17 8l-8 5c-2-3-5-5-9-5-6 0-10 4-10 10zm83-29v46h-9V5h9zM37 0l37 64H0L37 0zm92 5-27 48L74 5h10l18 30 17-30h10zm59 12v10l-3-1c-6 0-10 4-10 10v15h-9V17h9v9c0-5 6-9 13-9z"/></svg>
 | 
				
			||||||
| 
		 After Width: | Height: | Size: 629 B  | 
							
								
								
									
										80
									
								
								apps/webui/tailwind.config.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								apps/webui/tailwind.config.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,80 @@
 | 
				
			|||||||
 | 
					import type { Config } from "tailwindcss"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const config = {
 | 
				
			||||||
 | 
					  darkMode: ["class"],
 | 
				
			||||||
 | 
					  content: [
 | 
				
			||||||
 | 
					    './pages/**/*.{ts,tsx}',
 | 
				
			||||||
 | 
					    './components/**/*.{ts,tsx}',
 | 
				
			||||||
 | 
					    './app/**/*.{ts,tsx}',
 | 
				
			||||||
 | 
					    './src/**/*.{ts,tsx}',
 | 
				
			||||||
 | 
						],
 | 
				
			||||||
 | 
					  prefix: "",
 | 
				
			||||||
 | 
					  theme: {
 | 
				
			||||||
 | 
					    container: {
 | 
				
			||||||
 | 
					      center: true,
 | 
				
			||||||
 | 
					      padding: "2rem",
 | 
				
			||||||
 | 
					      screens: {
 | 
				
			||||||
 | 
					        "2xl": "1400px",
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    extend: {
 | 
				
			||||||
 | 
					      colors: {
 | 
				
			||||||
 | 
					        border: "hsl(var(--border))",
 | 
				
			||||||
 | 
					        input: "hsl(var(--input))",
 | 
				
			||||||
 | 
					        ring: "hsl(var(--ring))",
 | 
				
			||||||
 | 
					        background: "hsl(var(--background))",
 | 
				
			||||||
 | 
					        foreground: "hsl(var(--foreground))",
 | 
				
			||||||
 | 
					        primary: {
 | 
				
			||||||
 | 
					          DEFAULT: "hsl(var(--primary))",
 | 
				
			||||||
 | 
					          foreground: "hsl(var(--primary-foreground))",
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        secondary: {
 | 
				
			||||||
 | 
					          DEFAULT: "hsl(var(--secondary))",
 | 
				
			||||||
 | 
					          foreground: "hsl(var(--secondary-foreground))",
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        destructive: {
 | 
				
			||||||
 | 
					          DEFAULT: "hsl(var(--destructive))",
 | 
				
			||||||
 | 
					          foreground: "hsl(var(--destructive-foreground))",
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        muted: {
 | 
				
			||||||
 | 
					          DEFAULT: "hsl(var(--muted))",
 | 
				
			||||||
 | 
					          foreground: "hsl(var(--muted-foreground))",
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        accent: {
 | 
				
			||||||
 | 
					          DEFAULT: "hsl(var(--accent))",
 | 
				
			||||||
 | 
					          foreground: "hsl(var(--accent-foreground))",
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        popover: {
 | 
				
			||||||
 | 
					          DEFAULT: "hsl(var(--popover))",
 | 
				
			||||||
 | 
					          foreground: "hsl(var(--popover-foreground))",
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        card: {
 | 
				
			||||||
 | 
					          DEFAULT: "hsl(var(--card))",
 | 
				
			||||||
 | 
					          foreground: "hsl(var(--card-foreground))",
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      borderRadius: {
 | 
				
			||||||
 | 
					        lg: "var(--radius)",
 | 
				
			||||||
 | 
					        md: "calc(var(--radius) - 2px)",
 | 
				
			||||||
 | 
					        sm: "calc(var(--radius) - 4px)",
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      keyframes: {
 | 
				
			||||||
 | 
					        "accordion-down": {
 | 
				
			||||||
 | 
					          from: { height: "0" },
 | 
				
			||||||
 | 
					          to: { height: "var(--radix-accordion-content-height)" },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "accordion-up": {
 | 
				
			||||||
 | 
					          from: { height: "var(--radix-accordion-content-height)" },
 | 
				
			||||||
 | 
					          to: { height: "0" },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      animation: {
 | 
				
			||||||
 | 
					        "accordion-down": "accordion-down 0.2s ease-out",
 | 
				
			||||||
 | 
					        "accordion-up": "accordion-up 0.2s ease-out",
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  plugins: [require("tailwindcss-animate")],
 | 
				
			||||||
 | 
					} satisfies Config
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default config
 | 
				
			||||||
							
								
								
									
										40
									
								
								apps/webui/tsconfig.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								apps/webui/tsconfig.json
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,40 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "compilerOptions": {
 | 
				
			||||||
 | 
					    "lib": [
 | 
				
			||||||
 | 
					      "dom",
 | 
				
			||||||
 | 
					      "dom.iterable",
 | 
				
			||||||
 | 
					      "esnext"
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    "allowJs": true,
 | 
				
			||||||
 | 
					    "skipLibCheck": true,
 | 
				
			||||||
 | 
					    "strict": true,
 | 
				
			||||||
 | 
					    "noEmit": true,
 | 
				
			||||||
 | 
					    "esModuleInterop": true,
 | 
				
			||||||
 | 
					    "module": "esnext",
 | 
				
			||||||
 | 
					    "moduleResolution": "bundler",
 | 
				
			||||||
 | 
					    "resolveJsonModule": true,
 | 
				
			||||||
 | 
					    "isolatedModules": true,
 | 
				
			||||||
 | 
					    "jsx": "preserve",
 | 
				
			||||||
 | 
					    "incremental": true,
 | 
				
			||||||
 | 
					    "plugins": [
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        "name": "next"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    "paths": {
 | 
				
			||||||
 | 
					      "@/*": [
 | 
				
			||||||
 | 
					        "./*"
 | 
				
			||||||
 | 
					      ]
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "include": [
 | 
				
			||||||
 | 
					    "next-env.d.ts",
 | 
				
			||||||
 | 
					    "**/*.ts",
 | 
				
			||||||
 | 
					    "**/*.tsx",
 | 
				
			||||||
 | 
					    ".next/types/**/*.ts",
 | 
				
			||||||
 | 
					    "next.config.mjs"
 | 
				
			||||||
 | 
					  ],
 | 
				
			||||||
 | 
					  "exclude": [
 | 
				
			||||||
 | 
					    "node_modules"
 | 
				
			||||||
 | 
					  ]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										113
									
								
								config/recorder.development.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								config/recorder.development.yaml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,113 @@
 | 
				
			|||||||
 | 
					# Loco configuration file documentation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Application logging configuration
 | 
				
			||||||
 | 
					logger:
 | 
				
			||||||
 | 
					  # Enable or disable logging.
 | 
				
			||||||
 | 
					  enable: true
 | 
				
			||||||
 | 
					  # Enable pretty backtrace (sets RUST_BACKTRACE=1)
 | 
				
			||||||
 | 
					  pretty_backtrace: true
 | 
				
			||||||
 | 
					  # Log level, options: trace, debug, info, warn or error.
 | 
				
			||||||
 | 
					  level: debug
 | 
				
			||||||
 | 
					  # Define the logging format. options: compact, pretty or Json
 | 
				
			||||||
 | 
					  format: compact
 | 
				
			||||||
 | 
					  # By default the logger has filtering only logs that came from your code or logs that came from `loco` framework. to see all third party libraries
 | 
				
			||||||
 | 
					  # Uncomment the line below to override to see all third party libraries you can enable this config and override the logger filters.
 | 
				
			||||||
 | 
					  # override_filter: trace
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Web server configuration
 | 
				
			||||||
 | 
					server:
 | 
				
			||||||
 | 
					  # Port on which the server will listen. the server binding is 0.0.0.0:{PORT}
 | 
				
			||||||
 | 
					  port: 3001
 | 
				
			||||||
 | 
					  # The UI hostname or IP address that mailers will point to.
 | 
				
			||||||
 | 
					  host: http://webui.konobangu.com
 | 
				
			||||||
 | 
					  # Out of the box middleware configuration. to disable middleware you can changed the `enable` field to `false` of comment the middleware block
 | 
				
			||||||
 | 
					  middlewares:
 | 
				
			||||||
 | 
					    # Enable Etag cache header middleware
 | 
				
			||||||
 | 
					    etag:
 | 
				
			||||||
 | 
					      enable: true
 | 
				
			||||||
 | 
					    # Allows to limit the payload size request. payload that bigger than this file will blocked the request.
 | 
				
			||||||
 | 
					    limit_payload:
 | 
				
			||||||
 | 
					      # Enable/Disable the middleware.
 | 
				
			||||||
 | 
					      enable: true
 | 
				
			||||||
 | 
					      # the limit size. can be b,kb,kib,mb,mib,gb,gib
 | 
				
			||||||
 | 
					      body_limit: 5mb
 | 
				
			||||||
 | 
					    # Generating a unique request ID and enhancing logging with additional information such as the start and completion of request processing, latency, status code, and other request details.
 | 
				
			||||||
 | 
					    logger:
 | 
				
			||||||
 | 
					      # Enable/Disable the middleware.
 | 
				
			||||||
 | 
					      enable: true
 | 
				
			||||||
 | 
					    # when your code is panicked, the request still returns 500 status code.
 | 
				
			||||||
 | 
					    catch_panic:
 | 
				
			||||||
 | 
					      # Enable/Disable the middleware.
 | 
				
			||||||
 | 
					      enable: true
 | 
				
			||||||
 | 
					    # Timeout for incoming requests middleware. requests that take more time from the configuration will cute and 408 status code will returned.
 | 
				
			||||||
 | 
					    timeout_request:
 | 
				
			||||||
 | 
					      # Enable/Disable the middleware.
 | 
				
			||||||
 | 
					      enable: false
 | 
				
			||||||
 | 
					      # Duration time in milliseconds.
 | 
				
			||||||
 | 
					      timeout: 5000
 | 
				
			||||||
 | 
					    cors:
 | 
				
			||||||
 | 
					      enable: true
 | 
				
			||||||
 | 
					      # Set the value of the [`Access-Control-Allow-Origin`][mdn] header
 | 
				
			||||||
 | 
					      # allow_origins:
 | 
				
			||||||
 | 
					      #   - https://loco.rs
 | 
				
			||||||
 | 
					      # Set the value of the [`Access-Control-Allow-Headers`][mdn] header
 | 
				
			||||||
 | 
					      # allow_headers:
 | 
				
			||||||
 | 
					      # - Content-Type
 | 
				
			||||||
 | 
					      # Set the value of the [`Access-Control-Allow-Methods`][mdn] header
 | 
				
			||||||
 | 
					      # allow_methods:
 | 
				
			||||||
 | 
					      #   - POST
 | 
				
			||||||
 | 
					      # Set the value of the [`Access-Control-Max-Age`][mdn] header in seconds
 | 
				
			||||||
 | 
					      # max_age: 3600
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Worker Configuration
 | 
				
			||||||
 | 
					workers:
 | 
				
			||||||
 | 
					  # specifies the worker mode. Options:
 | 
				
			||||||
 | 
					  #   - BackgroundQueue - Workers operate asynchronously in the background, processing queued.
 | 
				
			||||||
 | 
					  #   - ForegroundBlocking - Workers operate in the foreground and block until tasks are completed.
 | 
				
			||||||
 | 
					  #   - BackgroundAsync - Workers operate asynchronously in the background, processing tasks with async capabilities.
 | 
				
			||||||
 | 
					  mode: BackgroundQueue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Mailer Configuration.
 | 
				
			||||||
 | 
					mailer:
 | 
				
			||||||
 | 
					  # SMTP mailer configuration.
 | 
				
			||||||
 | 
					  smtp:
 | 
				
			||||||
 | 
					    # Enable/Disable smtp mailer.
 | 
				
			||||||
 | 
					    enable: true
 | 
				
			||||||
 | 
					    # SMTP server host. e.x localhost, smtp.gmail.com
 | 
				
			||||||
 | 
					    host: '{{ get_env(name="MAILER_HOST", default="localhost") }}'
 | 
				
			||||||
 | 
					    # SMTP server port
 | 
				
			||||||
 | 
					    port: 1025
 | 
				
			||||||
 | 
					    # Use secure connection (SSL/TLS).
 | 
				
			||||||
 | 
					    secure: false
 | 
				
			||||||
 | 
					    # auth:
 | 
				
			||||||
 | 
					    #   user:
 | 
				
			||||||
 | 
					    #   password:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Database Configuration
 | 
				
			||||||
 | 
					database:
 | 
				
			||||||
 | 
					  # Database connection URI
 | 
				
			||||||
 | 
					  uri: '{{ get_env(name="DATABASE_URL", default="postgres://konobangu:konobangu@localhost:5432/konobangu") }}'
 | 
				
			||||||
 | 
					  # When enabled, the sql query will be logged.
 | 
				
			||||||
 | 
					  enable_logging: false
 | 
				
			||||||
 | 
					  # Set the timeout duration when acquiring a connection.
 | 
				
			||||||
 | 
					  connect_timeout: 500
 | 
				
			||||||
 | 
					  # Set the idle duration before closing a connection.
 | 
				
			||||||
 | 
					  idle_timeout: 500
 | 
				
			||||||
 | 
					  # Minimum number of connections for a pool.
 | 
				
			||||||
 | 
					  min_connections: 1
 | 
				
			||||||
 | 
					  # Maximum number of connections for a pool.
 | 
				
			||||||
 | 
					  max_connections: 1
 | 
				
			||||||
 | 
					  # Run migration up when application loaded
 | 
				
			||||||
 | 
					  auto_migrate: true
 | 
				
			||||||
 | 
					  # Truncate database when application loaded. This is a dangerous operation, make sure that you using this flag only on dev environments or test mode
 | 
				
			||||||
 | 
					  dangerously_truncate: false
 | 
				
			||||||
 | 
					  # Recreating schema when application loaded.  This is a dangerous operation, make sure that you using this flag only on dev environments or test mode
 | 
				
			||||||
 | 
					  dangerously_recreate: false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Redis Configuration
 | 
				
			||||||
 | 
					redis:
 | 
				
			||||||
 | 
					  # Redis connection URI
 | 
				
			||||||
 | 
					  uri: '{{ get_env(name="REDIS_URL", default="redis://127.0.0.1") }}'
 | 
				
			||||||
 | 
					  # Dangerously flush all data in Redis on startup. dangerous operation, make sure that you using this flag only on dev environments or test mode
 | 
				
			||||||
 | 
					  dangerously_flush: false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										0
									
								
								config/recorder.production.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								config/recorder.production.yaml
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										118
									
								
								config/recorder.test.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										118
									
								
								config/recorder.test.yaml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,118 @@
 | 
				
			|||||||
 | 
					# Loco configuration file documentation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Application logging configuration
 | 
				
			||||||
 | 
					logger:
 | 
				
			||||||
 | 
					  # Enable or disable logging.
 | 
				
			||||||
 | 
					  enable: false
 | 
				
			||||||
 | 
					  # Log level, options: trace, debug, info, warn or error.
 | 
				
			||||||
 | 
					  level: debug
 | 
				
			||||||
 | 
					  # Define the logging format. options: compact, pretty or Json
 | 
				
			||||||
 | 
					  format: compact
 | 
				
			||||||
 | 
					  # By default the logger has filtering only logs that came from your code or logs that came from `loco` framework. to see all third party libraries
 | 
				
			||||||
 | 
					  # Uncomment the line below to override to see all third party libraries you can enable this config and override the logger filters.
 | 
				
			||||||
 | 
					  # override_filter: trace
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Web server configuration
 | 
				
			||||||
 | 
					server:
 | 
				
			||||||
 | 
					  # Port on which the server will listen. the server binding is 0.0.0.0:{PORT}
 | 
				
			||||||
 | 
					  port: 3000
 | 
				
			||||||
 | 
					  # The UI hostname or IP address that mailers will point to.
 | 
				
			||||||
 | 
					  host: http://localhost
 | 
				
			||||||
 | 
					  # Out of the box middleware configuration. to disable middleware you can changed the `enable` field to `false` of comment the middleware block
 | 
				
			||||||
 | 
					  middlewares:
 | 
				
			||||||
 | 
					    # Allows to limit the payload size request. payload that bigger than this file will blocked the request.
 | 
				
			||||||
 | 
					    limit_payload:
 | 
				
			||||||
 | 
					      # Enable/Disable the middleware.
 | 
				
			||||||
 | 
					      enable: true
 | 
				
			||||||
 | 
					      # the limit size. can be b,kb,kib,mb,mib,gb,gib
 | 
				
			||||||
 | 
					      body_limit: 5mb
 | 
				
			||||||
 | 
					    # Generating a unique request ID and enhancing logging with additional information such as the start and completion of request processing, latency, status code, and other request details.
 | 
				
			||||||
 | 
					    logger:
 | 
				
			||||||
 | 
					      # Enable/Disable the middleware.
 | 
				
			||||||
 | 
					      enable: true
 | 
				
			||||||
 | 
					    # when your code is panicked, the request still returns 500 status code.
 | 
				
			||||||
 | 
					    catch_panic:
 | 
				
			||||||
 | 
					      # Enable/Disable the middleware.
 | 
				
			||||||
 | 
					      enable: true
 | 
				
			||||||
 | 
					    # Timeout for incoming requests middleware. requests that take more time from the configuration will cute and 408 status code will returned.
 | 
				
			||||||
 | 
					    timeout_request:
 | 
				
			||||||
 | 
					      # Enable/Disable the middleware.
 | 
				
			||||||
 | 
					      enable: false
 | 
				
			||||||
 | 
					      # Duration time in milliseconds.
 | 
				
			||||||
 | 
					      timeout: 5000
 | 
				
			||||||
 | 
					    cors:
 | 
				
			||||||
 | 
					      enable: true
 | 
				
			||||||
 | 
					      # Set the value of the [`Access-Control-Allow-Origin`][mdn] header
 | 
				
			||||||
 | 
					      # allow_origins:
 | 
				
			||||||
 | 
					      #   - https://loco.rs
 | 
				
			||||||
 | 
					      # Set the value of the [`Access-Control-Allow-Headers`][mdn] header
 | 
				
			||||||
 | 
					      # allow_headers:
 | 
				
			||||||
 | 
					      # - Content-Type
 | 
				
			||||||
 | 
					      # Set the value of the [`Access-Control-Allow-Methods`][mdn] header
 | 
				
			||||||
 | 
					      # allow_methods:
 | 
				
			||||||
 | 
					      #   - POST
 | 
				
			||||||
 | 
					      # Set the value of the [`Access-Control-Max-Age`][mdn] header in seconds
 | 
				
			||||||
 | 
					      # max_age: 3600
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Worker Configuration
 | 
				
			||||||
 | 
					workers:
 | 
				
			||||||
 | 
					  # specifies the worker mode. Options:
 | 
				
			||||||
 | 
					  #   - BackgroundQueue - Workers operate asynchronously in the background, processing queued.
 | 
				
			||||||
 | 
					  #   - ForegroundBlocking - Workers operate in the foreground and block until tasks are completed.
 | 
				
			||||||
 | 
					  #   - BackgroundAsync - Workers operate asynchronously in the background, processing tasks with async capabilities.
 | 
				
			||||||
 | 
					  mode: ForegroundBlocking
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Mailer Configuration.
 | 
				
			||||||
 | 
					mailer:
 | 
				
			||||||
 | 
					  # SMTP mailer configuration.
 | 
				
			||||||
 | 
					  smtp:
 | 
				
			||||||
 | 
					    # Enable/Disable smtp mailer.
 | 
				
			||||||
 | 
					    enable: true
 | 
				
			||||||
 | 
					    # SMTP server host. e.x localhost, smtp.gmail.com
 | 
				
			||||||
 | 
					    host: localhost
 | 
				
			||||||
 | 
					    # SMTP server port
 | 
				
			||||||
 | 
					    port: 1025
 | 
				
			||||||
 | 
					    # Use secure connection (SSL/TLS).
 | 
				
			||||||
 | 
					    secure: false
 | 
				
			||||||
 | 
					    # auth:
 | 
				
			||||||
 | 
					    #   user:
 | 
				
			||||||
 | 
					    #   password:
 | 
				
			||||||
 | 
					  stub: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Database Configuration
 | 
				
			||||||
 | 
					database:
 | 
				
			||||||
 | 
					  # Database connection URI
 | 
				
			||||||
 | 
					  uri: {{get_env(name="DATABASE_URL", default="postgres://loco:loco@localhost:5432/recorder_test")}} 
 | 
				
			||||||
 | 
					  # When enabled, the sql query will be logged.
 | 
				
			||||||
 | 
					  enable_logging: false
 | 
				
			||||||
 | 
					  # Set the timeout duration when acquiring a connection.
 | 
				
			||||||
 | 
					  connect_timeout: 500
 | 
				
			||||||
 | 
					  # Set the idle duration before closing a connection.
 | 
				
			||||||
 | 
					  idle_timeout: 500
 | 
				
			||||||
 | 
					  # Minimum number of connections for a pool.
 | 
				
			||||||
 | 
					  min_connections: 1
 | 
				
			||||||
 | 
					  # Maximum number of connections for a pool.
 | 
				
			||||||
 | 
					  max_connections: 1
 | 
				
			||||||
 | 
					  # Run migration up when application loaded
 | 
				
			||||||
 | 
					  auto_migrate: true
 | 
				
			||||||
 | 
					  # Truncate database when application loaded. This is a dangerous operation, make sure that you using this flag only on dev environments or test mode
 | 
				
			||||||
 | 
					  dangerously_truncate: true
 | 
				
			||||||
 | 
					  # Recreating schema when application loaded.  This is a dangerous operation, make sure that you using this flag only on dev environments or test mode
 | 
				
			||||||
 | 
					  dangerously_recreate: false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Redis Configuration
 | 
				
			||||||
 | 
					redis:
 | 
				
			||||||
 | 
					  # Redis connection URI
 | 
				
			||||||
 | 
					  uri: {{get_env(name="REDIS_URL", default="redis://127.0.0.1")}}
 | 
				
			||||||
 | 
					  # Dangerously flush all data in Redis on startup. dangerous operation, make sure that you using this flag only on dev environments or test mode
 | 
				
			||||||
 | 
					  dangerously_flush: false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Authentication Configuration
 | 
				
			||||||
 | 
					auth:
 | 
				
			||||||
 | 
					  # JWT authentication
 | 
				
			||||||
 | 
					  jwt:
 | 
				
			||||||
 | 
					    # Secret key for token generation and verification
 | 
				
			||||||
 | 
					    secret: ZknFYqXpnDgaWcKJZ5J5
 | 
				
			||||||
 | 
					    # Token expiration time in seconds
 | 
				
			||||||
 | 
					    expiration: 604800 # 7 days
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										8
									
								
								crates/recorder/.devcontainer/Dockerfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								crates/recorder/.devcontainer/Dockerfile
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					FROM mcr.microsoft.com/vscode/devcontainers/rust:0-1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
 | 
				
			||||||
 | 
					     && apt-get -y install --no-install-recommends postgresql-client \
 | 
				
			||||||
 | 
					     && cargo install sea-orm-cli cargo-insta \
 | 
				
			||||||
 | 
					     && chown -R vscode /usr/local/cargo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					COPY .env /.env
 | 
				
			||||||
							
								
								
									
										9
									
								
								crates/recorder/.devcontainer/devcontainer.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								crates/recorder/.devcontainer/devcontainer.json
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					    "name": "Konobangu Recorder",
 | 
				
			||||||
 | 
					    "dockerComposeFile": "docker-compose.yml",
 | 
				
			||||||
 | 
					    "service": "app",
 | 
				
			||||||
 | 
					    "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
 | 
				
			||||||
 | 
					    "forwardPorts": [
 | 
				
			||||||
 | 
					        3001
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										40
									
								
								crates/recorder/.devcontainer/docker-compose.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								crates/recorder/.devcontainer/docker-compose.yml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,40 @@
 | 
				
			|||||||
 | 
					version: "3"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					services:
 | 
				
			||||||
 | 
					  app:
 | 
				
			||||||
 | 
					    build:
 | 
				
			||||||
 | 
					      context: .
 | 
				
			||||||
 | 
					      dockerfile: Dockerfile
 | 
				
			||||||
 | 
					    command: sleep infinity
 | 
				
			||||||
 | 
					    networks:
 | 
				
			||||||
 | 
					      - db
 | 
				
			||||||
 | 
					      - redis
 | 
				
			||||||
 | 
					    volumes:
 | 
				
			||||||
 | 
					      - ../..:/workspaces:cached
 | 
				
			||||||
 | 
					    env_file:
 | 
				
			||||||
 | 
					      - .env
 | 
				
			||||||
 | 
					  db:
 | 
				
			||||||
 | 
					    image: postgres:15.3-alpine
 | 
				
			||||||
 | 
					    restart: unless-stopped
 | 
				
			||||||
 | 
					    ports:
 | 
				
			||||||
 | 
					      - 5432:5432
 | 
				
			||||||
 | 
					    networks:
 | 
				
			||||||
 | 
					      - db
 | 
				
			||||||
 | 
					    volumes:
 | 
				
			||||||
 | 
					      - postgres-data:/var/lib/postgresql/data
 | 
				
			||||||
 | 
					    env_file:
 | 
				
			||||||
 | 
					      - .env
 | 
				
			||||||
 | 
					  redis:
 | 
				
			||||||
 | 
					    image: redis:latest
 | 
				
			||||||
 | 
					    restart: unless-stopped
 | 
				
			||||||
 | 
					    ports:
 | 
				
			||||||
 | 
					      - 6379:6379
 | 
				
			||||||
 | 
					    networks:
 | 
				
			||||||
 | 
					      - redis
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					volumes:
 | 
				
			||||||
 | 
					  postgres-data:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					networks:
 | 
				
			||||||
 | 
					  db:
 | 
				
			||||||
 | 
					  redis:
 | 
				
			||||||
							
								
								
									
										107
									
								
								crates/recorder/.github/workflows/ci.yaml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								crates/recorder/.github/workflows/ci.yaml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,107 @@
 | 
				
			|||||||
 | 
					name: CI
 | 
				
			||||||
 | 
					on:
 | 
				
			||||||
 | 
					  push:
 | 
				
			||||||
 | 
					    branches:
 | 
				
			||||||
 | 
					      - master
 | 
				
			||||||
 | 
					      - main
 | 
				
			||||||
 | 
					  pull_request:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					env:
 | 
				
			||||||
 | 
					  RUST_TOOLCHAIN: stable
 | 
				
			||||||
 | 
					  TOOLCHAIN_PROFILE: minimal
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					jobs:
 | 
				
			||||||
 | 
					  rustfmt:
 | 
				
			||||||
 | 
					    name: Check Style
 | 
				
			||||||
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    permissions:
 | 
				
			||||||
 | 
					      contents: read
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    steps:
 | 
				
			||||||
 | 
					      - name: Checkout the code
 | 
				
			||||||
 | 
					        uses: actions/checkout@v4
 | 
				
			||||||
 | 
					      - uses: actions-rs/toolchain@v1
 | 
				
			||||||
 | 
					        with:
 | 
				
			||||||
 | 
					          profile: ${{ env.TOOLCHAIN_PROFILE }}
 | 
				
			||||||
 | 
					          toolchain: ${{ env.RUST_TOOLCHAIN }}
 | 
				
			||||||
 | 
					          override: true
 | 
				
			||||||
 | 
					          components: rustfmt
 | 
				
			||||||
 | 
					      - name: Run cargo fmt
 | 
				
			||||||
 | 
					        uses: actions-rs/cargo@v1
 | 
				
			||||||
 | 
					        with:
 | 
				
			||||||
 | 
					          command: fmt
 | 
				
			||||||
 | 
					          args: --all -- --check
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  clippy:
 | 
				
			||||||
 | 
					    name: Run Clippy
 | 
				
			||||||
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    permissions:
 | 
				
			||||||
 | 
					      contents: read
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    steps:
 | 
				
			||||||
 | 
					      - name: Checkout the code
 | 
				
			||||||
 | 
					        uses: actions/checkout@v4
 | 
				
			||||||
 | 
					      - uses: actions-rs/toolchain@v1
 | 
				
			||||||
 | 
					        with:
 | 
				
			||||||
 | 
					          profile: ${{ env.TOOLCHAIN_PROFILE }}
 | 
				
			||||||
 | 
					          toolchain: ${{ env.RUST_TOOLCHAIN }}
 | 
				
			||||||
 | 
					          override: true
 | 
				
			||||||
 | 
					      - name: Setup Rust cache
 | 
				
			||||||
 | 
					        uses: Swatinem/rust-cache@v2
 | 
				
			||||||
 | 
					      - name: Run cargo clippy
 | 
				
			||||||
 | 
					        uses: actions-rs/cargo@v1
 | 
				
			||||||
 | 
					        with:
 | 
				
			||||||
 | 
					          command: clippy
 | 
				
			||||||
 | 
					          args: --all-features -- -D warnings -W clippy::pedantic -W clippy::nursery -W rust-2018-idioms
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  test:
 | 
				
			||||||
 | 
					    name: Run Tests
 | 
				
			||||||
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    permissions:
 | 
				
			||||||
 | 
					      contents: read
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    services:
 | 
				
			||||||
 | 
					      redis:
 | 
				
			||||||
 | 
					        image: redis
 | 
				
			||||||
 | 
					        options: >-
 | 
				
			||||||
 | 
					          --health-cmd "redis-cli ping"
 | 
				
			||||||
 | 
					          --health-interval 10s
 | 
				
			||||||
 | 
					          --health-timeout 5s
 | 
				
			||||||
 | 
					          --health-retries 5
 | 
				
			||||||
 | 
					        ports:
 | 
				
			||||||
 | 
					          - "6379:6379"
 | 
				
			||||||
 | 
					      postgres:
 | 
				
			||||||
 | 
					        image: postgres
 | 
				
			||||||
 | 
					        env:
 | 
				
			||||||
 | 
					          POSTGRES_DB: postgress_test
 | 
				
			||||||
 | 
					          POSTGRES_USER: postgress
 | 
				
			||||||
 | 
					          POSTGRES_PASSWORD: postgress
 | 
				
			||||||
 | 
					        ports:
 | 
				
			||||||
 | 
					          - "5432:5432"
 | 
				
			||||||
 | 
					        # Set health checks to wait until postgres has started
 | 
				
			||||||
 | 
					        options: --health-cmd pg_isready
 | 
				
			||||||
 | 
					          --health-interval 10s
 | 
				
			||||||
 | 
					          --health-timeout 5s
 | 
				
			||||||
 | 
					          --health-retries 5
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    steps:
 | 
				
			||||||
 | 
					      - name: Checkout the code
 | 
				
			||||||
 | 
					        uses: actions/checkout@v4
 | 
				
			||||||
 | 
					      - uses: actions-rs/toolchain@v1
 | 
				
			||||||
 | 
					        with:
 | 
				
			||||||
 | 
					          profile: ${{ env.TOOLCHAIN_PROFILE }}
 | 
				
			||||||
 | 
					          toolchain: ${{ env.RUST_TOOLCHAIN }}
 | 
				
			||||||
 | 
					          override: true
 | 
				
			||||||
 | 
					      - name: Setup Rust cache
 | 
				
			||||||
 | 
					        uses: Swatinem/rust-cache@v2
 | 
				
			||||||
 | 
					      - name: Run cargo test
 | 
				
			||||||
 | 
					        uses: actions-rs/cargo@v1
 | 
				
			||||||
 | 
					        with:
 | 
				
			||||||
 | 
					          command: test
 | 
				
			||||||
 | 
					          args: --all-features --all
 | 
				
			||||||
 | 
					        env:
 | 
				
			||||||
 | 
					          REDIS_URL: redis://localhost:${{job.services.redis.ports[6379]}}
 | 
				
			||||||
 | 
					          DATABASE_URL: postgres://postgress:postgress@localhost:5432/postgress_test
 | 
				
			||||||
							
								
								
									
										17
									
								
								crates/recorder/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								crates/recorder/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,17 @@
 | 
				
			|||||||
 | 
					**/config/local.yaml
 | 
				
			||||||
 | 
					**/config/*.local.yaml
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Generated by Cargo
 | 
				
			||||||
 | 
					# will have compiled files and executables
 | 
				
			||||||
 | 
					debug/
 | 
				
			||||||
 | 
					target/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
 | 
				
			||||||
 | 
					# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
 | 
				
			||||||
 | 
					Cargo.lock
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# These are backup files generated by rustfmt
 | 
				
			||||||
 | 
					**/*.rs.bk
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# MSVC Windows builds of rustc generate these, which store debugging information
 | 
				
			||||||
 | 
					*.pdb
 | 
				
			||||||
							
								
								
									
										50
									
								
								crates/recorder/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								crates/recorder/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,50 @@
 | 
				
			|||||||
 | 
					[package]
 | 
				
			||||||
 | 
					name = "recorder"
 | 
				
			||||||
 | 
					version = "0.1.0"
 | 
				
			||||||
 | 
					edition = "2021"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[dependencies]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					loco-rs = { version = "0.3.1" }
 | 
				
			||||||
 | 
					serde = { version = "1", features = ["derive"] }
 | 
				
			||||||
 | 
					serde_json = "1"
 | 
				
			||||||
 | 
					eyre = "0.6"
 | 
				
			||||||
 | 
					tokio = { version = "1.33.0", default-features = false }
 | 
				
			||||||
 | 
					async-trait = "0.1.74"
 | 
				
			||||||
 | 
					tracing = "0.1.40"
 | 
				
			||||||
 | 
					chrono = "0.4"
 | 
				
			||||||
 | 
					validator = { version = "0.16" }
 | 
				
			||||||
 | 
					sea-orm = { version = "1.0.0-rc.1", features = [
 | 
				
			||||||
 | 
					  "sqlx-sqlite",
 | 
				
			||||||
 | 
					  "sqlx-postgres",
 | 
				
			||||||
 | 
					  "runtime-tokio-rustls",
 | 
				
			||||||
 | 
					  "macros",
 | 
				
			||||||
 | 
					] }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					axum = "0.7.1"
 | 
				
			||||||
 | 
					include_dir = "0.7"
 | 
				
			||||||
 | 
					uuid = { version = "1.6.0", features = ["v4"] }
 | 
				
			||||||
 | 
					tracing-subscriber = { version = "0.3.17", features = ["env-filter", "json"] }
 | 
				
			||||||
 | 
					sea-orm-migration = { version = "1.0.0-rc.1", features = [
 | 
				
			||||||
 | 
					  "runtime-tokio-rustls",
 | 
				
			||||||
 | 
					] }
 | 
				
			||||||
 | 
					reqwest = "0.11.24"
 | 
				
			||||||
 | 
					thiserror = "1.0.57"
 | 
				
			||||||
 | 
					rss = "2.0.7"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[lib]
 | 
				
			||||||
 | 
					name = "recorder"
 | 
				
			||||||
 | 
					path = "src/lib.rs"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[bin]]
 | 
				
			||||||
 | 
					name = "recorder_cli"
 | 
				
			||||||
 | 
					path = "src/bin/main.rs"
 | 
				
			||||||
 | 
					required-features = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[dev-dependencies]
 | 
				
			||||||
 | 
					serial_test = "2.0.0"
 | 
				
			||||||
 | 
					rstest = "0.18.2"
 | 
				
			||||||
 | 
					loco-rs = { version = "0.3.1", features = ["testing"] }
 | 
				
			||||||
 | 
					insta = { version = "1.34.0", features = ["redactions", "yaml", "filters"] }
 | 
				
			||||||
							
								
								
									
										33
									
								
								crates/recorder/examples/playground.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								crates/recorder/examples/playground.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,33 @@
 | 
				
			|||||||
 | 
					use eyre::Context;
 | 
				
			||||||
 | 
					#[allow(unused_imports)]
 | 
				
			||||||
 | 
					use loco_rs::{cli::playground, prelude::*};
 | 
				
			||||||
 | 
					use recorder::app::App;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async fn fetch_and_parse_rss_demo () -> eyre::Result<()> {
 | 
				
			||||||
 | 
					    let url =
 | 
				
			||||||
 | 
					    "https://mikanani.me/RSS/MyBangumi?token=FE9tccsML2nBPUUqpCuJW2uJZydAXCntHJ7RpD9LDP8%3d";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let res = reqwest::get(url).await?.bytes().await?;
 | 
				
			||||||
 | 
					    let channel = rss::Channel::read_from(&res[..])?;
 | 
				
			||||||
 | 
					    println!("channel: {:#?}", channel);
 | 
				
			||||||
 | 
					    Ok(())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[tokio::main]
 | 
				
			||||||
 | 
					async fn main() -> eyre::Result<()> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fetch_and_parse_rss_demo().await?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // let active_model: articles::ActiveModel = ActiveModel {
 | 
				
			||||||
 | 
					    //     title: Set(Some("how to build apps in 3 steps".to_string())),
 | 
				
			||||||
 | 
					    //     content: Set(Some("use Loco: https://loco.rs".to_string())),
 | 
				
			||||||
 | 
					    //     ..Default::default()
 | 
				
			||||||
 | 
					    // };
 | 
				
			||||||
 | 
					    // active_model.insert(&ctx.db).await.unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // let res = articles::Entity::find().all(&ctx.db).await.unwrap();
 | 
				
			||||||
 | 
					    // println!("{:?}", res);
 | 
				
			||||||
 | 
					    println!("welcome to playground. edit me at `examples/playground.rs`");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Ok(())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										62
									
								
								crates/recorder/src/app.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								crates/recorder/src/app.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,62 @@
 | 
				
			|||||||
 | 
					use std::path::Path;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use async_trait::async_trait;
 | 
				
			||||||
 | 
					use loco_rs::{
 | 
				
			||||||
 | 
					    app::{AppContext, Hooks},
 | 
				
			||||||
 | 
					    boot::{create_app, BootResult, StartMode},
 | 
				
			||||||
 | 
					    controller::AppRoutes,
 | 
				
			||||||
 | 
					    db::truncate_table,
 | 
				
			||||||
 | 
					    environment::Environment,
 | 
				
			||||||
 | 
					    task::Tasks,
 | 
				
			||||||
 | 
					    worker::{AppWorker, Processor},
 | 
				
			||||||
 | 
					    Result,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					use sea_orm::DatabaseConnection;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::{
 | 
				
			||||||
 | 
					    controllers, migrations::Migrator, models::_entities::subscribers,
 | 
				
			||||||
 | 
					    workers::downloader::DownloadWorker,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub struct App;
 | 
				
			||||||
 | 
					#[async_trait]
 | 
				
			||||||
 | 
					impl Hooks for App {
 | 
				
			||||||
 | 
					    fn app_name() -> &'static str {
 | 
				
			||||||
 | 
					        env!("CARGO_CRATE_NAME")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn app_version() -> String {
 | 
				
			||||||
 | 
					        format!(
 | 
				
			||||||
 | 
					            "{} ({})",
 | 
				
			||||||
 | 
					            env!("CARGO_PKG_VERSION"),
 | 
				
			||||||
 | 
					            option_env!("BUILD_SHA")
 | 
				
			||||||
 | 
					                .or(option_env!("GITHUB_SHA"))
 | 
				
			||||||
 | 
					                .unwrap_or("dev")
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    async fn boot(mode: StartMode, environment: &Environment) -> Result<BootResult> {
 | 
				
			||||||
 | 
					        create_app::<Self, Migrator>(mode, environment).await
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn routes(_ctx: &AppContext) -> AppRoutes {
 | 
				
			||||||
 | 
					        AppRoutes::with_default_routes()
 | 
				
			||||||
 | 
					            .prefix("/api")
 | 
				
			||||||
 | 
					            .add_route(controllers::subscribers::routes())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn connect_workers<'a>(p: &'a mut Processor, ctx: &'a AppContext) {
 | 
				
			||||||
 | 
					        p.register(DownloadWorker::build(ctx));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn register_tasks(_tasks: &mut Tasks) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    async fn truncate(db: &DatabaseConnection) -> Result<()> {
 | 
				
			||||||
 | 
					        truncate_table(db, subscribers::Entity).await?;
 | 
				
			||||||
 | 
					        Ok(())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    async fn seed(_db: &DatabaseConnection, _base: &Path) -> Result<()> {
 | 
				
			||||||
 | 
					        Ok(())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										8
									
								
								crates/recorder/src/bin/main.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								crates/recorder/src/bin/main.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					use loco_rs::cli;
 | 
				
			||||||
 | 
					use recorder::migrations::Migrator;
 | 
				
			||||||
 | 
					use recorder::app::App;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[tokio::main]
 | 
				
			||||||
 | 
					async fn main() -> eyre::Result<()> {
 | 
				
			||||||
 | 
					    cli::main::<App, Migrator>().await
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										1
									
								
								crates/recorder/src/controllers/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								crates/recorder/src/controllers/mod.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					pub mod subscribers;
 | 
				
			||||||
							
								
								
									
										14
									
								
								crates/recorder/src/controllers/subscribers.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								crates/recorder/src/controllers/subscribers.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					use loco_rs::prelude::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::{models::_entities::subscribers, views::subscribers::CurrentResponse};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async fn current(State(ctx): State<AppContext>) -> Result<Json<CurrentResponse>> {
 | 
				
			||||||
 | 
					    let subscriber = subscribers::Model::find_root(&ctx.db).await?;
 | 
				
			||||||
 | 
					    format::json(CurrentResponse::new(&subscriber))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn routes() -> Routes {
 | 
				
			||||||
 | 
					    Routes::new()
 | 
				
			||||||
 | 
					        .prefix("subscribers")
 | 
				
			||||||
 | 
					        .add("/current", get(current))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										0
									
								
								crates/recorder/src/downloader/aria.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								crates/recorder/src/downloader/aria.rs
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										2
									
								
								crates/recorder/src/downloader/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								crates/recorder/src/downloader/mod.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,2 @@
 | 
				
			|||||||
 | 
					pub mod aria;
 | 
				
			||||||
 | 
					pub mod qbitorrent;
 | 
				
			||||||
							
								
								
									
										0
									
								
								crates/recorder/src/downloader/qbitorrent.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								crates/recorder/src/downloader/qbitorrent.rs
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										10
									
								
								crates/recorder/src/lib.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								crates/recorder/src/lib.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					pub mod app;
 | 
				
			||||||
 | 
					pub mod controllers;
 | 
				
			||||||
 | 
					pub mod downloader;
 | 
				
			||||||
 | 
					pub mod migrations;
 | 
				
			||||||
 | 
					pub mod models;
 | 
				
			||||||
 | 
					pub mod rss;
 | 
				
			||||||
 | 
					pub mod subscriptions;
 | 
				
			||||||
 | 
					pub mod tasks;
 | 
				
			||||||
 | 
					pub mod views;
 | 
				
			||||||
 | 
					pub mod workers;
 | 
				
			||||||
							
								
								
									
										40
									
								
								crates/recorder/src/migrations/defs.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								crates/recorder/src/migrations/defs.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,40 @@
 | 
				
			|||||||
 | 
					use sea_orm_migration::prelude::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Iden)]
 | 
				
			||||||
 | 
					pub enum Subscribers {
 | 
				
			||||||
 | 
					    Table,
 | 
				
			||||||
 | 
					    Id,
 | 
				
			||||||
 | 
					    Pid,
 | 
				
			||||||
 | 
					    DisplayName,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Iden)]
 | 
				
			||||||
 | 
					pub enum Subscriptions {
 | 
				
			||||||
 | 
					    Table,
 | 
				
			||||||
 | 
					    Id,
 | 
				
			||||||
 | 
					    SubscriberId,
 | 
				
			||||||
 | 
					    DisplayName,
 | 
				
			||||||
 | 
					    Category,
 | 
				
			||||||
 | 
					    SourceUrl,
 | 
				
			||||||
 | 
					    Aggregate,
 | 
				
			||||||
 | 
					    Enabled,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Iden)]
 | 
				
			||||||
 | 
					pub enum Bangumi {
 | 
				
			||||||
 | 
					    Table,
 | 
				
			||||||
 | 
					    Id,
 | 
				
			||||||
 | 
					    DisplayName,
 | 
				
			||||||
 | 
					    SubscriptionId,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Iden)]
 | 
				
			||||||
 | 
					pub enum Episodes {
 | 
				
			||||||
 | 
					    Table,
 | 
				
			||||||
 | 
					    Id,
 | 
				
			||||||
 | 
					    DisplayName,
 | 
				
			||||||
 | 
					    BangumiId,
 | 
				
			||||||
 | 
					    DownloadUrl,
 | 
				
			||||||
 | 
					    DownloadProgress,
 | 
				
			||||||
 | 
					    OutputName,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										125
									
								
								crates/recorder/src/migrations/m20220101_000001_init.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								crates/recorder/src/migrations/m20220101_000001_init.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,125 @@
 | 
				
			|||||||
 | 
					use sea_orm::sea_query::extension::postgres::Type;
 | 
				
			||||||
 | 
					use sea_orm_migration::{prelude::*, schema::*};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use super::defs::{Bangumi, Episodes, Subscribers, Subscriptions};
 | 
				
			||||||
 | 
					use crate::models::subscribers::ROOT_SUBSCRIBER;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(DeriveMigrationName)]
 | 
				
			||||||
 | 
					pub struct Migration;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[async_trait::async_trait]
 | 
				
			||||||
 | 
					impl MigrationTrait for Migration {
 | 
				
			||||||
 | 
					    async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
 | 
				
			||||||
 | 
					        manager
 | 
				
			||||||
 | 
					            .create_table(
 | 
				
			||||||
 | 
					                table_auto(Subscribers::Table)
 | 
				
			||||||
 | 
					                    .col(pk_auto(Subscribers::Id))
 | 
				
			||||||
 | 
					                    .col(string_len_uniq(Subscribers::Pid, 64))
 | 
				
			||||||
 | 
					                    .col(string(Subscribers::DisplayName))
 | 
				
			||||||
 | 
					                    .to_owned(),
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					            .await?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let insert = Query::insert()
 | 
				
			||||||
 | 
					            .into_table(Subscribers::Table)
 | 
				
			||||||
 | 
					            .columns([Subscribers::Pid, Subscribers::DisplayName])
 | 
				
			||||||
 | 
					            .values_panic([ROOT_SUBSCRIBER.into(), ROOT_SUBSCRIBER.into()])
 | 
				
			||||||
 | 
					            .to_owned();
 | 
				
			||||||
 | 
					        manager.exec_stmt(insert).await?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        manager
 | 
				
			||||||
 | 
					            .create_type(
 | 
				
			||||||
 | 
					                Type::create()
 | 
				
			||||||
 | 
					                    .as_enum(Alias::new("subscription_category"))
 | 
				
			||||||
 | 
					                    .values([
 | 
				
			||||||
 | 
					                        Alias::new("mikan"),
 | 
				
			||||||
 | 
					                        Alias::new("manual"),
 | 
				
			||||||
 | 
					                        Alias::new("bangumi"),
 | 
				
			||||||
 | 
					                    ])
 | 
				
			||||||
 | 
					                    .to_owned(),
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					            .await?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        manager
 | 
				
			||||||
 | 
					            .create_table(
 | 
				
			||||||
 | 
					                table_auto(Subscriptions::Table)
 | 
				
			||||||
 | 
					                    .col(pk_auto(Subscriptions::Id))
 | 
				
			||||||
 | 
					                    .col(string(Subscriptions::DisplayName))
 | 
				
			||||||
 | 
					                    .col(integer(Subscriptions::SubscriberId))
 | 
				
			||||||
 | 
					                    .col(text(Subscriptions::SourceUrl))
 | 
				
			||||||
 | 
					                    .col(boolean(Subscriptions::Aggregate))
 | 
				
			||||||
 | 
					                    .col(boolean(Subscriptions::Enabled))
 | 
				
			||||||
 | 
					                    .foreign_key(
 | 
				
			||||||
 | 
					                        ForeignKey::create()
 | 
				
			||||||
 | 
					                            .name("subscription_subscriber_id")
 | 
				
			||||||
 | 
					                            .from(Subscriptions::Table, Subscriptions::SubscriberId)
 | 
				
			||||||
 | 
					                            .to(Subscribers::Table, Subscribers::Id),
 | 
				
			||||||
 | 
					                    )
 | 
				
			||||||
 | 
					                    .to_owned(),
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					            .await?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        manager
 | 
				
			||||||
 | 
					            .create_table(
 | 
				
			||||||
 | 
					                table_auto(Bangumi::Table)
 | 
				
			||||||
 | 
					                    .col(pk_auto(Bangumi::Id))
 | 
				
			||||||
 | 
					                    .col(text(Bangumi::DisplayName))
 | 
				
			||||||
 | 
					                    .col(integer(Bangumi::SubscriptionId))
 | 
				
			||||||
 | 
					                    .foreign_key(
 | 
				
			||||||
 | 
					                        ForeignKey::create()
 | 
				
			||||||
 | 
					                            .name("bangumi_subscription_id")
 | 
				
			||||||
 | 
					                            .from(Bangumi::Table, Bangumi::SubscriptionId)
 | 
				
			||||||
 | 
					                            .to(Subscriptions::Table, Subscriptions::Id),
 | 
				
			||||||
 | 
					                    )
 | 
				
			||||||
 | 
					                    .to_owned(),
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					            .await?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        manager
 | 
				
			||||||
 | 
					            .create_table(
 | 
				
			||||||
 | 
					                table_auto(Episodes::Table)
 | 
				
			||||||
 | 
					                    .col(pk_auto(Episodes::Id))
 | 
				
			||||||
 | 
					                    .col(text(Episodes::DisplayName))
 | 
				
			||||||
 | 
					                    .col(integer(Episodes::BangumiId))
 | 
				
			||||||
 | 
					                    .col(text(Episodes::DownloadUrl))
 | 
				
			||||||
 | 
					                    .col(tiny_integer(Episodes::DownloadProgress).default(0))
 | 
				
			||||||
 | 
					                    .col(text(Episodes::OutputName))
 | 
				
			||||||
 | 
					                    .foreign_key(
 | 
				
			||||||
 | 
					                        ForeignKey::create()
 | 
				
			||||||
 | 
					                            .name("episode_bangumi_id")
 | 
				
			||||||
 | 
					                            .from(Episodes::Table, Episodes::BangumiId)
 | 
				
			||||||
 | 
					                            .to(Bangumi::Table, Bangumi::Id),
 | 
				
			||||||
 | 
					                    )
 | 
				
			||||||
 | 
					                    .to_owned(),
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					            .await?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Ok(())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
 | 
				
			||||||
 | 
					        manager
 | 
				
			||||||
 | 
					            .drop_table(Table::drop().table(Episodes::Table).to_owned())
 | 
				
			||||||
 | 
					            .await?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        manager
 | 
				
			||||||
 | 
					            .drop_table(Table::drop().table(Bangumi::Table).to_owned())
 | 
				
			||||||
 | 
					            .await?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        manager
 | 
				
			||||||
 | 
					            .drop_table(Table::drop().table(Subscriptions::Table).to_owned())
 | 
				
			||||||
 | 
					            .await?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        manager
 | 
				
			||||||
 | 
					            .drop_type(
 | 
				
			||||||
 | 
					                Type::drop()
 | 
				
			||||||
 | 
					                    .name(Alias::new("subscription_category"))
 | 
				
			||||||
 | 
					                    .to_owned(),
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					            .await?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        manager
 | 
				
			||||||
 | 
					            .drop_table(Table::drop().table(Subscribers::Table).to_owned())
 | 
				
			||||||
 | 
					            .await
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										13
									
								
								crates/recorder/src/migrations/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								crates/recorder/src/migrations/mod.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,13 @@
 | 
				
			|||||||
 | 
					pub use sea_orm_migration::prelude::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub mod defs;
 | 
				
			||||||
 | 
					pub mod m20220101_000001_init;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub struct Migrator;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[async_trait::async_trait]
 | 
				
			||||||
 | 
					impl MigratorTrait for Migrator {
 | 
				
			||||||
 | 
					    fn migrations() -> Vec<Box<dyn MigrationTrait>> {
 | 
				
			||||||
 | 
					        vec![Box::new(m20220101_000001_init::Migration)]
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										39
									
								
								crates/recorder/src/models/_entities/bangumi.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								crates/recorder/src/models/_entities/bangumi.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,39 @@
 | 
				
			|||||||
 | 
					//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use sea_orm::entity::prelude::*;
 | 
				
			||||||
 | 
					use serde::{Deserialize, Serialize};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 | 
				
			||||||
 | 
					#[sea_orm(table_name = "bangumi")]
 | 
				
			||||||
 | 
					pub struct Model {
 | 
				
			||||||
 | 
					    pub created_at: DateTime,
 | 
				
			||||||
 | 
					    pub updated_at: DateTime,
 | 
				
			||||||
 | 
					    #[sea_orm(primary_key)]
 | 
				
			||||||
 | 
					    pub id: i32,
 | 
				
			||||||
 | 
					    pub display_name: String,
 | 
				
			||||||
 | 
					    pub subscription_id: i32,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
 | 
				
			||||||
 | 
					pub enum Relation {
 | 
				
			||||||
 | 
					    #[sea_orm(
 | 
				
			||||||
 | 
					        belongs_to = "super::subscriptions::Entity",
 | 
				
			||||||
 | 
					        from = "Column::SubscriptionId",
 | 
				
			||||||
 | 
					        to = "super::subscriptions::Column::Id"
 | 
				
			||||||
 | 
					    )]
 | 
				
			||||||
 | 
					    Subscription,
 | 
				
			||||||
 | 
					    #[sea_orm(has_many = "super::episodes::Entity")]
 | 
				
			||||||
 | 
					    Episode,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Related<super::episodes::Entity> for Entity {
 | 
				
			||||||
 | 
					    fn to() -> RelationDef {
 | 
				
			||||||
 | 
					        Relation::Episode.def()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Related<super::subscriptions::Entity> for Entity {
 | 
				
			||||||
 | 
					    fn to() -> RelationDef {
 | 
				
			||||||
 | 
					        Relation::Subscription.def()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										34
									
								
								crates/recorder/src/models/_entities/episodes.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								crates/recorder/src/models/_entities/episodes.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,34 @@
 | 
				
			|||||||
 | 
					//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use sea_orm::entity::prelude::*;
 | 
				
			||||||
 | 
					use serde::{Deserialize, Serialize};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 | 
				
			||||||
 | 
					#[sea_orm(table_name = "episodes")]
 | 
				
			||||||
 | 
					pub struct Model {
 | 
				
			||||||
 | 
					    pub created_at: DateTime,
 | 
				
			||||||
 | 
					    pub updated_at: DateTime,
 | 
				
			||||||
 | 
					    #[sea_orm(primary_key)]
 | 
				
			||||||
 | 
					    pub id: i32,
 | 
				
			||||||
 | 
					    pub display_name: String,
 | 
				
			||||||
 | 
					    pub bangumi_id: i32,
 | 
				
			||||||
 | 
					    pub download_url: String,
 | 
				
			||||||
 | 
					    pub download_progress: i32,
 | 
				
			||||||
 | 
					    pub output_name: String,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
 | 
				
			||||||
 | 
					pub enum Relation {
 | 
				
			||||||
 | 
					    #[sea_orm(
 | 
				
			||||||
 | 
					        belongs_to = "super::bangumi::Entity",
 | 
				
			||||||
 | 
					        from = "Column::BangumiId",
 | 
				
			||||||
 | 
					        to = "super::bangumi::Column::Id"
 | 
				
			||||||
 | 
					    )]
 | 
				
			||||||
 | 
					    Bangumi,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Related<super::bangumi::Entity> for Entity {
 | 
				
			||||||
 | 
					    fn to() -> RelationDef {
 | 
				
			||||||
 | 
					        Relation::Bangumi.def()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										8
									
								
								crates/recorder/src/models/_entities/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								crates/recorder/src/models/_entities/mod.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub mod prelude;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub mod bangumi;
 | 
				
			||||||
 | 
					pub mod episodes;
 | 
				
			||||||
 | 
					pub mod subscribers;
 | 
				
			||||||
 | 
					pub mod subscriptions;
 | 
				
			||||||
							
								
								
									
										6
									
								
								crates/recorder/src/models/_entities/prelude.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								crates/recorder/src/models/_entities/prelude.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub use super::{
 | 
				
			||||||
 | 
					    bangumi::Entity as Bangumi, episodes::Entity as Episodes, subscribers::Entity as Subscribers,
 | 
				
			||||||
 | 
					    subscriptions::Entity as Subscriptions,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										28
									
								
								crates/recorder/src/models/_entities/subscribers.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								crates/recorder/src/models/_entities/subscribers.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,28 @@
 | 
				
			|||||||
 | 
					//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use sea_orm::entity::prelude::*;
 | 
				
			||||||
 | 
					use serde::{Deserialize, Serialize};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 | 
				
			||||||
 | 
					#[sea_orm(table_name = "subscribers")]
 | 
				
			||||||
 | 
					pub struct Model {
 | 
				
			||||||
 | 
					    pub created_at: DateTime,
 | 
				
			||||||
 | 
					    pub updated_at: DateTime,
 | 
				
			||||||
 | 
					    #[sea_orm(primary_key)]
 | 
				
			||||||
 | 
					    pub id: i32,
 | 
				
			||||||
 | 
					    #[sea_orm(unique)]
 | 
				
			||||||
 | 
					    pub pid: String,
 | 
				
			||||||
 | 
					    pub display_name: String,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
 | 
				
			||||||
 | 
					pub enum Relation {
 | 
				
			||||||
 | 
					    #[sea_orm(has_many = "super::subscriptions::Entity")]
 | 
				
			||||||
 | 
					    Subscription,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Related<super::subscriptions::Entity> for Entity {
 | 
				
			||||||
 | 
					    fn to() -> RelationDef {
 | 
				
			||||||
 | 
					        Relation::Subscription.def()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										59
									
								
								crates/recorder/src/models/_entities/subscriptions.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								crates/recorder/src/models/_entities/subscriptions.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,59 @@
 | 
				
			|||||||
 | 
					//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use sea_orm::entity::prelude::*;
 | 
				
			||||||
 | 
					use serde::{Deserialize, Serialize};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Clone, Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)]
 | 
				
			||||||
 | 
					#[sea_orm(
 | 
				
			||||||
 | 
					    rs_type = "String",
 | 
				
			||||||
 | 
					    db_type = "Enum",
 | 
				
			||||||
 | 
					    enum_name = "subscription_category"
 | 
				
			||||||
 | 
					)]
 | 
				
			||||||
 | 
					#[serde(rename_all = "snake_case")]
 | 
				
			||||||
 | 
					pub enum SubscriptionCategory {
 | 
				
			||||||
 | 
					    #[sea_orm(string_value = "mikan")]
 | 
				
			||||||
 | 
					    Mikan,
 | 
				
			||||||
 | 
					    #[sea_orm(string_value = "manual")]
 | 
				
			||||||
 | 
					    Manual,
 | 
				
			||||||
 | 
					    #[sea_orm(string_value = "bangumi")]
 | 
				
			||||||
 | 
					    Bangumi,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 | 
				
			||||||
 | 
					#[sea_orm(table_name = "subscriptions")]
 | 
				
			||||||
 | 
					pub struct Model {
 | 
				
			||||||
 | 
					    pub created_at: DateTime,
 | 
				
			||||||
 | 
					    pub updated_at: DateTime,
 | 
				
			||||||
 | 
					    #[sea_orm(primary_key)]
 | 
				
			||||||
 | 
					    pub id: i32,
 | 
				
			||||||
 | 
					    pub display_name: String,
 | 
				
			||||||
 | 
					    pub subscriber_id: i32,
 | 
				
			||||||
 | 
					    pub category: SubscriptionCategory,
 | 
				
			||||||
 | 
					    pub source_url: String,
 | 
				
			||||||
 | 
					    pub aggregate: bool,
 | 
				
			||||||
 | 
					    pub enabled: bool,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
 | 
				
			||||||
 | 
					pub enum Relation {
 | 
				
			||||||
 | 
					    #[sea_orm(
 | 
				
			||||||
 | 
					        belongs_to = "super::subscribers::Entity",
 | 
				
			||||||
 | 
					        from = "Column::SubscriberId",
 | 
				
			||||||
 | 
					        to = "super::subscribers::Column::Id"
 | 
				
			||||||
 | 
					    )]
 | 
				
			||||||
 | 
					    Subscriber,
 | 
				
			||||||
 | 
					    #[sea_orm(has_many = "super::bangumi::Entity")]
 | 
				
			||||||
 | 
					    Bangumi,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Related<super::subscribers::Entity> for Entity {
 | 
				
			||||||
 | 
					    fn to() -> RelationDef {
 | 
				
			||||||
 | 
					        Relation::Subscriber.def()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Related<super::bangumi::Entity> for Entity {
 | 
				
			||||||
 | 
					    fn to() -> RelationDef {
 | 
				
			||||||
 | 
					        Relation::Bangumi.def()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										6
									
								
								crates/recorder/src/models/bangumi.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								crates/recorder/src/models/bangumi.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					use sea_orm::entity::prelude::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub use super::_entities::bangumi::{self, ActiveModel, Entity, Model};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[async_trait::async_trait]
 | 
				
			||||||
 | 
					impl ActiveModelBehavior for super::_entities::bangumi::ActiveModel {}
 | 
				
			||||||
							
								
								
									
										6
									
								
								crates/recorder/src/models/episodes.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								crates/recorder/src/models/episodes.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					use sea_orm::entity::prelude::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub use super::_entities::episodes::{self, ActiveModel, Entity, Model};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[async_trait::async_trait]
 | 
				
			||||||
 | 
					impl ActiveModelBehavior for super::_entities::episodes::ActiveModel {}
 | 
				
			||||||
							
								
								
									
										5
									
								
								crates/recorder/src/models/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								crates/recorder/src/models/mod.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					pub mod _entities;
 | 
				
			||||||
 | 
					pub mod bangumi;
 | 
				
			||||||
 | 
					pub mod episodes;
 | 
				
			||||||
 | 
					pub mod subscribers;
 | 
				
			||||||
 | 
					pub mod subscriptions;
 | 
				
			||||||
							
								
								
									
										70
									
								
								crates/recorder/src/models/subscribers.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								crates/recorder/src/models/subscribers.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,70 @@
 | 
				
			|||||||
 | 
					use loco_rs::model::{ModelError, ModelResult};
 | 
				
			||||||
 | 
					use sea_orm::{entity::prelude::*, ActiveValue, TransactionTrait};
 | 
				
			||||||
 | 
					use serde::{Deserialize, Serialize};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub use super::_entities::subscribers::{self, ActiveModel, Entity, Model};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub const ROOT_SUBSCRIBER: &str = "konobangu";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, Deserialize, Serialize)]
 | 
				
			||||||
 | 
					pub struct SubscriberIdParams {
 | 
				
			||||||
 | 
					    pub id: String,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[async_trait::async_trait]
 | 
				
			||||||
 | 
					impl ActiveModelBehavior for super::_entities::subscribers::ActiveModel {
 | 
				
			||||||
 | 
					    async fn before_save<C>(self, _db: &C, insert: bool) -> Result<Self, DbErr>
 | 
				
			||||||
 | 
					    where
 | 
				
			||||||
 | 
					        C: ConnectionTrait,
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if insert {
 | 
				
			||||||
 | 
					            let mut this = self;
 | 
				
			||||||
 | 
					            this.pid = ActiveValue::Set(Uuid::new_v4().to_string());
 | 
				
			||||||
 | 
					            Ok(this)
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            Ok(self)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl super::_entities::subscribers::Model {
 | 
				
			||||||
 | 
					    /// finds a user by the provided pid
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// # Errors
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// When could not find user  or DB query error
 | 
				
			||||||
 | 
					    pub async fn find_by_pid(db: &DatabaseConnection, pid: &str) -> ModelResult<Self> {
 | 
				
			||||||
 | 
					        let parse_uuid = Uuid::parse_str(pid).map_err(|e| ModelError::Any(e.into()))?;
 | 
				
			||||||
 | 
					        let subscriber = subscribers::Entity::find()
 | 
				
			||||||
 | 
					            .filter(subscribers::Column::Pid.eq(parse_uuid))
 | 
				
			||||||
 | 
					            .one(db)
 | 
				
			||||||
 | 
					            .await?;
 | 
				
			||||||
 | 
					        subscriber.ok_or_else(|| ModelError::EntityNotFound)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub async fn find_root(db: &DatabaseConnection) -> ModelResult<Self> {
 | 
				
			||||||
 | 
					        Self::find_by_pid(db, ROOT_SUBSCRIBER).await
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Asynchronously creates a user with a password and saves it to the
 | 
				
			||||||
 | 
					    /// database.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// # Errors
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// When could not save the user into the DB
 | 
				
			||||||
 | 
					    pub async fn create_root(db: &DatabaseConnection) -> ModelResult<Self> {
 | 
				
			||||||
 | 
					        let txn = db.begin().await?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let user = subscribers::ActiveModel {
 | 
				
			||||||
 | 
					            display_name: ActiveValue::set(ROOT_SUBSCRIBER.to_string()),
 | 
				
			||||||
 | 
					            pid: ActiveValue::set(ROOT_SUBSCRIBER.to_string()),
 | 
				
			||||||
 | 
					            ..Default::default()
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        .insert(&txn)
 | 
				
			||||||
 | 
					        .await?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        txn.commit().await?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Ok(user)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										6
									
								
								crates/recorder/src/models/subscriptions.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								crates/recorder/src/models/subscriptions.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					use sea_orm::entity::prelude::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub use super::_entities::subscriptions::{self, ActiveModel, Entity, Model};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[async_trait::async_trait]
 | 
				
			||||||
 | 
					impl ActiveModelBehavior for super::_entities::subscriptions::ActiveModel {}
 | 
				
			||||||
							
								
								
									
										23
									
								
								crates/recorder/src/rss/engine.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								crates/recorder/src/rss/engine.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,23 @@
 | 
				
			|||||||
 | 
					use serde::{Deserialize, Serialize};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::models::subscriptions::subscriptions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, Clone, Serialize, Deserialize)]
 | 
				
			||||||
 | 
					pub struct RssTorrent {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug)]
 | 
				
			||||||
 | 
					pub struct RssEngine {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl RssEngine {
 | 
				
			||||||
 | 
					    // pub async fn get_rss_torrents(
 | 
				
			||||||
 | 
					    //     rss_subscription: &subscriptions::ActiveModel,
 | 
				
			||||||
 | 
					    // ) -> eyre::Result<Vec<RssTorrent>> {
 | 
				
			||||||
 | 
					    //     Ok(())
 | 
				
			||||||
 | 
					    // }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub async fn get_torrents(url: &str) -> eyre::Result<rss::Channel> {
 | 
				
			||||||
 | 
					        let content = reqwest::get(url).await?.bytes().await?;
 | 
				
			||||||
 | 
					        let channel: rss::Channel = rss::Channel::read_from(&content[..])?;
 | 
				
			||||||
 | 
					        Ok(channel)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										1
									
								
								crates/recorder/src/rss/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								crates/recorder/src/rss/mod.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					pub mod engine;
 | 
				
			||||||
							
								
								
									
										1
									
								
								crates/recorder/src/subscriptions/bangumi.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								crates/recorder/src/subscriptions/bangumi.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										23
									
								
								crates/recorder/src/subscriptions/mikan.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								crates/recorder/src/subscriptions/mikan.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,23 @@
 | 
				
			|||||||
 | 
					use crate::rss::engine::RssEngine;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub struct MikanRssCreateDto {
 | 
				
			||||||
 | 
					    pub rss_link: String,
 | 
				
			||||||
 | 
					    pub display_name: String,
 | 
				
			||||||
 | 
					    pub aggregate: bool,
 | 
				
			||||||
 | 
					    pub enabled: Option<bool>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub struct MikanSubscriptionEngine {
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl MikanSubscriptionEngine {
 | 
				
			||||||
 | 
					    pub async fn add_rss(create_dto: MikanRssCreateDto) -> eyre::Result<()> {
 | 
				
			||||||
 | 
					        let content = reqwest::get(&create_dto.rss_link).await?.bytes().await?;
 | 
				
			||||||
 | 
					        let channel = rss::Channel::read_from(&content[..])?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Ok(())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub struct MikanSubscriptionItem {
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										2
									
								
								crates/recorder/src/subscriptions/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								crates/recorder/src/subscriptions/mod.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,2 @@
 | 
				
			|||||||
 | 
					pub mod bangumi;
 | 
				
			||||||
 | 
					pub mod mikan;
 | 
				
			||||||
							
								
								
									
										1
									
								
								crates/recorder/src/tasks/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								crates/recorder/src/tasks/mod.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										1
									
								
								crates/recorder/src/views/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								crates/recorder/src/views/mod.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					pub mod subscribers;
 | 
				
			||||||
							
								
								
									
										19
									
								
								crates/recorder/src/views/subscribers.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								crates/recorder/src/views/subscribers.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					use serde::{Deserialize, Serialize};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::models::_entities::subscribers;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, Deserialize, Serialize)]
 | 
				
			||||||
 | 
					pub struct CurrentResponse {
 | 
				
			||||||
 | 
					    pub pid: String,
 | 
				
			||||||
 | 
					    pub display_name: String,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl CurrentResponse {
 | 
				
			||||||
 | 
					    #[must_use]
 | 
				
			||||||
 | 
					    pub fn new(user: &subscribers::Model) -> Self {
 | 
				
			||||||
 | 
					        Self {
 | 
				
			||||||
 | 
					            pid: user.pid.to_string(),
 | 
				
			||||||
 | 
					            display_name: user.display_name.to_string(),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										43
									
								
								crates/recorder/src/workers/downloader.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								crates/recorder/src/workers/downloader.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,43 @@
 | 
				
			|||||||
 | 
					use std::time::Duration;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use loco_rs::prelude::*;
 | 
				
			||||||
 | 
					use serde::{Deserialize, Serialize};
 | 
				
			||||||
 | 
					use tokio::time::sleep;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::models::subscribers;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub struct DownloadWorker {
 | 
				
			||||||
 | 
					    pub ctx: AppContext,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Deserialize, Debug, Serialize)]
 | 
				
			||||||
 | 
					pub struct DownloadWorkerArgs {
 | 
				
			||||||
 | 
					    pub user_guid: String,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl worker::AppWorker<DownloadWorkerArgs> for DownloadWorker {
 | 
				
			||||||
 | 
					    fn build(ctx: &AppContext) -> Self {
 | 
				
			||||||
 | 
					        Self { ctx: ctx.clone() }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[async_trait]
 | 
				
			||||||
 | 
					impl worker::Worker<DownloadWorkerArgs> for DownloadWorker {
 | 
				
			||||||
 | 
					    async fn perform(&self, args: DownloadWorkerArgs) -> worker::Result<()> {
 | 
				
			||||||
 | 
					        // TODO: Some actual work goes here...
 | 
				
			||||||
 | 
					        println!("================================================");
 | 
				
			||||||
 | 
					        println!("Sending payment report to user {}", args.user_guid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        sleep(Duration::from_millis(2000)).await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let all = subscribers::Entity::find()
 | 
				
			||||||
 | 
					            .all(&self.ctx.db)
 | 
				
			||||||
 | 
					            .await
 | 
				
			||||||
 | 
					            .map_err(Box::from)?;
 | 
				
			||||||
 | 
					        for user in &all {
 | 
				
			||||||
 | 
					            println!("user: {}", user.id);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        println!("================================================");
 | 
				
			||||||
 | 
					        Ok(())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										1
									
								
								crates/recorder/src/workers/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								crates/recorder/src/workers/mod.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					pub mod downloader;
 | 
				
			||||||
							
								
								
									
										3
									
								
								crates/recorder/tests/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								crates/recorder/tests/mod.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					mod models;
 | 
				
			||||||
 | 
					mod requests;
 | 
				
			||||||
 | 
					mod tasks;
 | 
				
			||||||
							
								
								
									
										1
									
								
								crates/recorder/tests/models/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								crates/recorder/tests/models/mod.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					mod subscribers;
 | 
				
			||||||
@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					---
 | 
				
			||||||
 | 
					source: tests/models/subscribers.rs
 | 
				
			||||||
 | 
					expression: non_existing_subscriber_results
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					Err(
 | 
				
			||||||
 | 
					    EntityNotFound,
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
@ -0,0 +1,13 @@
 | 
				
			|||||||
 | 
					---
 | 
				
			||||||
 | 
					source: tests/models/subscribers.rs
 | 
				
			||||||
 | 
					expression: existing_subscriber
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					Ok(
 | 
				
			||||||
 | 
					    Model {
 | 
				
			||||||
 | 
					        created_at: 2023-11-12T12:34:56.789,
 | 
				
			||||||
 | 
					        updated_at: 2023-11-12T12:34:56.789,
 | 
				
			||||||
 | 
					        id: 1,
 | 
				
			||||||
 | 
					        pid: "11111111-1111-1111-1111-111111111111",
 | 
				
			||||||
 | 
					        display_name: "user1"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
							
								
								
									
										27
									
								
								crates/recorder/tests/models/subscribers.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								crates/recorder/tests/models/subscribers.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,27 @@
 | 
				
			|||||||
 | 
					use insta::assert_debug_snapshot;
 | 
				
			||||||
 | 
					use loco_rs::testing;
 | 
				
			||||||
 | 
					use recorder::{app::App, models::subscribers::Model};
 | 
				
			||||||
 | 
					use serial_test::serial;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					macro_rules! configure_insta {
 | 
				
			||||||
 | 
					    ($($expr:expr),*) => {
 | 
				
			||||||
 | 
					        let mut settings = insta::Settings::clone_current();
 | 
				
			||||||
 | 
					        settings.set_prepend_module_to_snapshot(false);
 | 
				
			||||||
 | 
					        settings.set_snapshot_suffix("users");
 | 
				
			||||||
 | 
					        let _guard = settings.bind_to_scope();
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[tokio::test]
 | 
				
			||||||
 | 
					#[serial]
 | 
				
			||||||
 | 
					async fn can_find_by_pid() {
 | 
				
			||||||
 | 
					    configure_insta!();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let boot = testing::boot_test::<App>().await.unwrap();
 | 
				
			||||||
 | 
					    testing::seed::<App>(&boot.app_context.db).await.unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let existing_subscriber =
 | 
				
			||||||
 | 
					        Model::find_by_pid(&boot.app_context.db, "11111111-1111-1111-1111-111111111111").await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert_debug_snapshot!(existing_subscriber);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										2
									
								
								crates/recorder/tests/requests/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								crates/recorder/tests/requests/mod.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,2 @@
 | 
				
			|||||||
 | 
					mod notes;
 | 
				
			||||||
 | 
					mod subscribers;
 | 
				
			||||||
							
								
								
									
										32
									
								
								crates/recorder/tests/requests/subscribers.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								crates/recorder/tests/requests/subscribers.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,32 @@
 | 
				
			|||||||
 | 
					use insta::{assert_debug_snapshot, with_settings};
 | 
				
			||||||
 | 
					use loco_rs::testing;
 | 
				
			||||||
 | 
					use recorder::app::App;
 | 
				
			||||||
 | 
					use serial_test::serial;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO: see how to dedup / extract this to app-local test utils
 | 
				
			||||||
 | 
					// not to framework, because that would require a runtime dep on insta
 | 
				
			||||||
 | 
					macro_rules! configure_insta {
 | 
				
			||||||
 | 
					    ($($expr:expr),*) => {
 | 
				
			||||||
 | 
					        let mut settings = insta::Settings::clone_current();
 | 
				
			||||||
 | 
					        settings.set_prepend_module_to_snapshot(false);
 | 
				
			||||||
 | 
					        settings.set_snapshot_suffix("user_request");
 | 
				
			||||||
 | 
					        let _guard = settings.bind_to_scope();
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[tokio::test]
 | 
				
			||||||
 | 
					#[serial]
 | 
				
			||||||
 | 
					async fn can_get_current_user() {
 | 
				
			||||||
 | 
					    configure_insta!();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    testing::request::<App, _, _>(|request, _ctx| async move {
 | 
				
			||||||
 | 
					        let response = request.get("/api/user/current").await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        with_settings!({
 | 
				
			||||||
 | 
					            filters => testing::cleanup_user_model()
 | 
				
			||||||
 | 
					        }, {
 | 
				
			||||||
 | 
					            assert_debug_snapshot!((response.status_code(), response.text()));
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    .await;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										1
									
								
								crates/recorder/tests/tasks/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								crates/recorder/tests/tasks/mod.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					pub mod seed;
 | 
				
			||||||
							
								
								
									
										43
									
								
								crates/recorder/tests/tasks/seed.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								crates/recorder/tests/tasks/seed.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,43 @@
 | 
				
			|||||||
 | 
					//! This task implements data seeding functionality for initializing new
 | 
				
			||||||
 | 
					//! development/demo environments.
 | 
				
			||||||
 | 
					//!
 | 
				
			||||||
 | 
					//! # Example
 | 
				
			||||||
 | 
					//!
 | 
				
			||||||
 | 
					//! Run the task with the following command:
 | 
				
			||||||
 | 
					//! ```sh
 | 
				
			||||||
 | 
					//! cargo run task
 | 
				
			||||||
 | 
					//! ```
 | 
				
			||||||
 | 
					//!
 | 
				
			||||||
 | 
					//! To override existing data and reset the data structure, use the following
 | 
				
			||||||
 | 
					//! command with the `refresh:true` argument:
 | 
				
			||||||
 | 
					//! ```sh
 | 
				
			||||||
 | 
					//! cargo run task seed_data refresh:true
 | 
				
			||||||
 | 
					//! ```
 | 
				
			||||||
 | 
					use std::collections::BTreeMap;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use loco_rs::{db, prelude::*};
 | 
				
			||||||
 | 
					use migration::Migrator;
 | 
				
			||||||
 | 
					use recorder::app::App;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[allow(clippy::module_name_repetitions)]
 | 
				
			||||||
 | 
					pub struct SeedData;
 | 
				
			||||||
 | 
					#[async_trait]
 | 
				
			||||||
 | 
					impl Task for SeedData {
 | 
				
			||||||
 | 
					    fn task(&self) -> TaskInfo {
 | 
				
			||||||
 | 
					        TaskInfo {
 | 
				
			||||||
 | 
					            name: "seed_data".to_string(),
 | 
				
			||||||
 | 
					            detail: "Task for seeding data".to_string(),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    async fn run(&self, app_context: &AppContext, vars: &BTreeMap<String, String>) -> Result<()> {
 | 
				
			||||||
 | 
					        let refresh = vars.get("refresh").is_some_and(|refresh| refresh == "true");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if refresh {
 | 
				
			||||||
 | 
					            db::reset::<Migrator>(&app_context.db).await?;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        let path = std::path::Path::new("src/fixtures");
 | 
				
			||||||
 | 
					        db::run_app_seed::<App>(&app_context.db, path).await?;
 | 
				
			||||||
 | 
					        Ok(())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										18
									
								
								justfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								justfile
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,18 @@
 | 
				
			|||||||
 | 
					set windows-shell := ["pwsh.exe", "-c"]
 | 
				
			||||||
 | 
					set dotenv-load
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					prepare-dev-recorder:
 | 
				
			||||||
 | 
					  cargo install loco-cli
 | 
				
			||||||
 | 
					  cargo install sea-orm-cli
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					dev-recorder:
 | 
				
			||||||
 | 
					  cargo watch -w crates/recorder -w config -x 'recorder start'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					play-recorder:
 | 
				
			||||||
 | 
					  cargo recorder-playground
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					dev-webui:
 | 
				
			||||||
 | 
					  npm run dev:webui
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					dev-proxy:
 | 
				
			||||||
 | 
					  npm run dev:proxy
 | 
				
			||||||
							
								
								
									
										34
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,34 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "name": "konobangu",
 | 
				
			||||||
 | 
					  "version": "0.0.0",
 | 
				
			||||||
 | 
					  "description": "Kono bangumi?",
 | 
				
			||||||
 | 
					  "workspaces": [
 | 
				
			||||||
 | 
					    "packages/*",
 | 
				
			||||||
 | 
					    "apps/*"
 | 
				
			||||||
 | 
					  ],
 | 
				
			||||||
 | 
					  "scripts": {
 | 
				
			||||||
 | 
					    "dev": "npm-run-all -p dev:proxy dev:webui",
 | 
				
			||||||
 | 
					    "dev:proxy": "npm run start -w apps/proxy",
 | 
				
			||||||
 | 
					    "dev:webui": "npm run dev -w apps/webui",
 | 
				
			||||||
 | 
					    "build:webui": "npm run build -w apps/webui"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "repository": {
 | 
				
			||||||
 | 
					    "type": "git",
 | 
				
			||||||
 | 
					    "url": "https://github.com/lonelyhentxi/konobangu.git"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "private": true,
 | 
				
			||||||
 | 
					  "dependencies": {
 | 
				
			||||||
 | 
					    "@datasert/cronjs-parser": "^1.4.0",
 | 
				
			||||||
 | 
					    "date-fns": "^3.3.1",
 | 
				
			||||||
 | 
					    "lodash-es": "^4.17.21",
 | 
				
			||||||
 | 
					    "nanoid": "^5.0.5",
 | 
				
			||||||
 | 
					    "rxjs": "~7.8.1"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "devDependencies": {
 | 
				
			||||||
 | 
					    "cross-env": "^7.0.3",
 | 
				
			||||||
 | 
					    "dotenv": "^16.4.3",
 | 
				
			||||||
 | 
					    "npm-run-all": "^4.1.5",
 | 
				
			||||||
 | 
					    "shx": "^0.3.4",
 | 
				
			||||||
 | 
					    "typescript": "^5.3.3"
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										4190
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										4190
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										3
									
								
								pnpm-workspace.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								pnpm-workspace.yaml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					packages:
 | 
				
			||||||
 | 
					  - "packages/*"
 | 
				
			||||||
 | 
					  - "apps/*"
 | 
				
			||||||
							
								
								
									
										4
									
								
								rust-toolchain.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								rust-toolchain.toml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,4 @@
 | 
				
			|||||||
 | 
					[toolchain]
 | 
				
			||||||
 | 
					channel = "nightly"
 | 
				
			||||||
 | 
					components = ["rustfmt", "clippy"]
 | 
				
			||||||
 | 
					profile = "default"
 | 
				
			||||||
							
								
								
									
										7
									
								
								rustfmt.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								rustfmt.toml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					max_width = 100
 | 
				
			||||||
 | 
					comment_width = 80
 | 
				
			||||||
 | 
					wrap_comments = true
 | 
				
			||||||
 | 
					imports_granularity = "Crate"
 | 
				
			||||||
 | 
					use_small_heuristics = "Default"
 | 
				
			||||||
 | 
					group_imports = "StdExternalCrate"
 | 
				
			||||||
 | 
					format_strings = true
 | 
				
			||||||
							
								
								
									
										18
									
								
								src/tasks/rss_dl.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/tasks/rss_dl.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,18 @@
 | 
				
			|||||||
 | 
					use std::collections::BTreeMap;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use loco_rs::prelude::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub struct RssDl;
 | 
				
			||||||
 | 
					#[async_trait]
 | 
				
			||||||
 | 
					impl Task for RssDl {
 | 
				
			||||||
 | 
					    fn task(&self) -> TaskInfo {
 | 
				
			||||||
 | 
					        TaskInfo {
 | 
				
			||||||
 | 
					            name: "rss_dl".to_string(),
 | 
				
			||||||
 | 
					            detail: "Task generator".to_string(),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    async fn run(&self, _app_context: &AppContext, _vars: &BTreeMap<String, String>) -> Result<()> {
 | 
				
			||||||
 | 
					        println!("Task RssDl generated");
 | 
				
			||||||
 | 
					        Ok(())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user