├── .all-contributorsrc ├── .env ├── .github └── workflows │ ├── build-release.yml │ ├── codeql.yml │ ├── commit-check.yml │ ├── dependency-review.yml │ └── docker-dev.yml ├── .gitignore ├── .goreleaser.yaml ├── Dockerfile ├── LICENSE ├── Makefile ├── README.md ├── app.go ├── config ├── config.go ├── default.go ├── env.go └── types.go ├── data ├── actions │ ├── handler.go │ ├── logging.go │ └── plugin.go ├── drivers │ ├── memory.go │ ├── mongo.go │ ├── mysql.go │ ├── postgres.go │ ├── redis.go │ ├── sqlite.go │ └── types.go ├── initializer.go └── models │ └── database.go ├── examples ├── example.lua └── plugin │ ├── gocqhttp.go │ └── webhook.go ├── go.mod ├── go.sum ├── internal ├── grpc │ └── gocqhttp.go ├── javascript │ └── gocqhttp.go ├── logging │ ├── gocqhttp.go │ └── gocqhttp │ │ ├── message.go │ │ └── types.go ├── lua │ ├── common │ │ ├── httpreq.go │ │ └── system.go │ ├── database │ │ └── plugin.go │ ├── gocqhttp.go │ ├── gocqhttp │ │ ├── action.go │ │ ├── cqcode.go │ │ ├── getdata.go │ │ ├── message.go │ │ └── request.go │ ├── runtime │ │ ├── loader.go │ │ ├── luavm.go │ │ └── scripts.go │ └── webhook.go └── mirai │ └── bot.go ├── logger └── logrus.go ├── pkg ├── database │ └── plugin.go ├── fastlib │ ├── fastcq │ │ ├── gocqhttp.go │ │ └── message.go │ └── system │ │ ├── info.go │ │ └── time.go ├── gocqhttp │ ├── callback │ │ ├── callback.go │ │ └── types.go │ ├── common │ │ ├── file.go │ │ ├── image.go │ │ ├── message.go │ │ └── voice.go │ ├── cqcode │ │ ├── cqcode.go │ │ └── decode.go │ ├── friend │ │ ├── actions.go │ │ └── message.go │ ├── group │ │ ├── actions.go │ │ ├── message.go │ │ └── settings.go │ ├── request.go │ ├── system │ │ ├── account.go │ │ ├── internal.go │ │ └── requests.go │ ├── types │ │ ├── account.go │ │ ├── actions.go │ │ ├── cqcode.go │ │ ├── file.go │ │ ├── forward.go │ │ ├── image.go │ │ ├── internal.go │ │ ├── message.go │ │ ├── requests.go │ │ ├── response.go │ │ ├── settings.go │ │ └── voice.go │ └── websocket │ │ ├── connector.go │ │ ├── request.go │ │ └── response.go ├── plugin │ ├── entry.go │ ├── plugin.go │ └── types.go └── webhook │ └── types.go ├── plugins └── .gitkeep ├── scripts └── .gitkeep ├── server ├── entry.go └── server.go └── utils └── request.go /.all-contributorsrc: -------------------------------------------------------------------------------- 1 | { 2 | "files": [ 3 | "README.md" 4 | ], 5 | "imageSize": 100, 6 | "commit": false, 7 | "commitConvention": "angular", 8 | "contributors": [ 9 | { 10 | "login": "WhiteElytra", 11 | "name": "BaiYi", 12 | "avatar_url": "https://avatars.githubusercontent.com/u/25338540?v=4", 13 | "profile": "http://baiyi.moe", 14 | "contributions": [ 15 | "code", 16 | "bug", 17 | "infra", 18 | "design", 19 | "projectManagement" 20 | ] 21 | }, 22 | { 23 | "login": "isNagatoYuki", 24 | "name": "isNagatoYuki", 25 | "avatar_url": "https://avatars.githubusercontent.com/u/54537867?v=4", 26 | "profile": "https://github.com/isNagatoYuki", 27 | "contributions": [ 28 | "bug", 29 | "code", 30 | "a11y" 31 | ] 32 | } 33 | ], 34 | "contributorsPerLine": 7, 35 | "skipCi": true, 36 | "repoType": "github", 37 | "repoHost": "https://github.com", 38 | "projectName": "NyaBot", 39 | "projectOwner": "Elyart-Network" 40 | } 41 | -------------------------------------------------------------------------------- /.env: -------------------------------------------------------------------------------- 1 | SERVER_LISTEN_PORT= 2 | SERVER_FILE_LOGGER= 3 | SERVER_DEBUG_MODE= 4 | SEARCH_ENABLE= 5 | SEARCH_HOST= 6 | SEARCH_INDEX_NAME= 7 | SEARCH_USERNAME= 8 | SEARCH_PASSWORD= 9 | MIRAI_ENABLE= 10 | LOGGING_EXTERNAL= 11 | LOGGING_MONGO_URI= 12 | LOGGING_USERNAME= 13 | LOGGING_PASSWORD= 14 | LOGGING_CACHE_NUM= 15 | LOGGING_INTERNAL_LOG= 16 | CACHE_EXTERNAL= 17 | CACHE_HOSTS= 18 | CACHE_MASTER= 19 | CACHE_USERNAME= 20 | CACHE_PASSWORD= 21 | DATABASE_TYPE= 22 | DATABASE_HOST= 23 | DATABASE_NAME= 24 | DATABASE_USERNAME= 25 | DATABASE_PASSWORD= 26 | GOCQHTTP_ENABLED= 27 | GOCQHTTP_HOST_URL= 28 | GOCQHTTP_DELAY= 29 | GOCQHTTP_ENABLE_WS= 30 | PLUGIN_LUA_ENABLE= 31 | PLUGIN_LUA_PATH= 32 | PLUGIN_LUA_SCTIPT_DIR= 33 | PLUGIN_LUA_SANDBOX= -------------------------------------------------------------------------------- /.github/workflows/build-release.yml: -------------------------------------------------------------------------------- 1 | # .github/workflows/release.yaml 2 | 3 | name: Build Release 4 | 5 | on: 6 | release: 7 | types: [created] 8 | 9 | jobs: 10 | release: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: checkout code 14 | uses: actions/checkout@v2 15 | with: 16 | submodules: 'true' 17 | - name: setup dependencies 18 | uses: actions/setup-go@v2 19 | - name: release dry run 20 | run: make release-dry-run 21 | - name: setup release environment 22 | run: |- 23 | echo 'GITHUB_TOKEN=${{secrets.GITHUB_TOKEN}}' > .release-env 24 | - name: release publish 25 | run: make release 26 | docker-hub: 27 | name: Build Docker Image 28 | runs-on: ubuntu-latest 29 | steps: 30 | - name: Checkout Repository 31 | uses: actions/checkout@v3 32 | - name: Set up QEMU 33 | uses: docker/setup-qemu-action@v2 34 | - name: Set up Docker Context for Buildx 35 | id: buildx-context 36 | run: | 37 | docker context create builders 38 | - name: Set up Docker Buildx 39 | uses: docker/setup-buildx-action@v2 40 | with: 41 | endpoint: builders 42 | - name: Login to Docker Hub 43 | uses: docker/login-action@v2 44 | with: 45 | username: ${{ secrets.DOCKERHUB_USERNAME }} 46 | password: ${{ secrets.DOCKERHUB_TOKEN }} 47 | - name: Build and push 48 | uses: docker/build-push-action@v4 49 | with: 50 | context: . 51 | platforms: linux/amd64,linux/arm64 52 | push: true 53 | tags: whydesd/nyabot:latest,whydesd/nyabot:${{ github.event.release.tag_name }} 54 | harbor: 55 | runs-on: ubuntu-20.04 56 | steps: 57 | - name: Checkout Repository 58 | uses: actions/checkout@v3 59 | - name: Set up QEMU 60 | uses: docker/setup-qemu-action@v2 61 | - name: Set up Docker Context for Buildx 62 | id: buildx-context 63 | run: | 64 | docker context create builders 65 | - name: Set up Docker Buildx 66 | uses: docker/setup-buildx-action@v2 67 | with: 68 | endpoint: builders 69 | - name: Login to Harbor 70 | uses: docker/login-action@v2 71 | with: 72 | registry: registry.infra.elyart.cn 73 | username: ${{ secrets.HARBOR_UNA }} 74 | password: ${{ secrets.HARBOR_PWD }} 75 | - name: Build and push 76 | uses: docker/build-push-action@v4 77 | with: 78 | context: . 79 | platforms: linux/amd64,linux/arm64 80 | push: true 81 | tags: registry.infra.elyart.cn/nyabot/nyabot-ce:${{ github.event.release.tag_name }} 82 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: [push, pull_request] 15 | 16 | jobs: 17 | analyze: 18 | name: Analyze 19 | runs-on: ubuntu-20.04 20 | permissions: 21 | actions: read 22 | contents: read 23 | security-events: write 24 | 25 | strategy: 26 | fail-fast: false 27 | matrix: 28 | language: [ 'go' ] 29 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] 30 | # Use only 'java' to analyze code written in Java, Kotlin or both 31 | # Use only 'javascript' to analyze code written in JavaScript, TypeScript or both 32 | # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support 33 | 34 | steps: 35 | - name: Checkout repository 36 | uses: actions/checkout@v3 37 | 38 | # Initializes the CodeQL tools for scanning. 39 | - name: Initialize CodeQL 40 | uses: github/codeql-action/init@v2 41 | with: 42 | languages: ${{ matrix.language }} 43 | # If you wish to specify custom queries, you can do so here or in a config file. 44 | # By default, queries listed here will override any specified in a config file. 45 | # Prefix the list here with "+" to use these queries and those in the config file. 46 | 47 | # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs 48 | # queries: security-extended,security-and-quality 49 | 50 | 51 | # Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java). 52 | # If this step fails, then you should remove it and run the build manually (see below) 53 | - name: Autobuild 54 | uses: github/codeql-action/autobuild@v2 55 | 56 | # ℹ️ Command-line programs to run using the OS shell. 57 | # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun 58 | 59 | # If the Autobuild fails above, remove it and uncomment the following three lines. 60 | # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. 61 | 62 | # - run: | 63 | # echo "Run, Build Application using script" 64 | # ./location_of_script_within_repo/buildscript.sh 65 | 66 | - name: Perform CodeQL Analysis 67 | uses: github/codeql-action/analyze@v2 68 | with: 69 | category: "/language:${{matrix.language}}" 70 | -------------------------------------------------------------------------------- /.github/workflows/commit-check.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build a golang project 2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go 3 | 4 | name: Commit Check 5 | 6 | on: [push, pull_request] 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-20.04 11 | steps: 12 | - uses: actions/checkout@v3 13 | 14 | - name: Set up Go 15 | uses: actions/setup-go@v3 16 | with: 17 | go-version: '1.20' 18 | 19 | - name: Build 20 | run: go build -v ./... 21 | env: 22 | GO111MODULE: on 23 | GOPROXY: direct 24 | 25 | - name: Test 26 | run: go test -v ./... 27 | env: 28 | GO111MODULE: on 29 | GOPROXY: direct -------------------------------------------------------------------------------- /.github/workflows/dependency-review.yml: -------------------------------------------------------------------------------- 1 | # Dependency Review Action 2 | # 3 | # This Action will scan dependency manifest files that change as part of a Pull Request, surfacing known-vulnerable versions of the packages declared or updated in the PR. Once installed, if the workflow run is marked as required, PRs introducing known-vulnerable packages will be blocked from merging. 4 | # 5 | # Source repository: https://github.com/actions/dependency-review-action 6 | # Public documentation: https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/about-dependency-review#dependency-review-enforcement 7 | name: 'Dependency Review' 8 | 9 | on: [pull_request] 10 | 11 | permissions: 12 | contents: read 13 | 14 | jobs: 15 | dependency-review: 16 | runs-on: ubuntu-20.04 17 | steps: 18 | - name: 'Checkout Repository' 19 | uses: actions/checkout@v3 20 | - name: 'Dependency Review' 21 | uses: actions/dependency-review-action@v2 22 | with: 23 | fail-on-severity: moderate 24 | -------------------------------------------------------------------------------- /.github/workflows/docker-dev.yml: -------------------------------------------------------------------------------- 1 | name: Docker Dev 2 | 3 | on: push 4 | 5 | jobs: 6 | docker-hub: 7 | runs-on: ubuntu-20.04 8 | steps: 9 | - 10 | name: Checkout Repository 11 | uses: actions/checkout@v3 12 | - 13 | name: Set up QEMU 14 | uses: docker/setup-qemu-action@v2 15 | - 16 | name: Set up Docker Context for Buildx 17 | id: buildx-context 18 | run: | 19 | docker context create builders 20 | - 21 | name: Set up Docker Buildx 22 | uses: docker/setup-buildx-action@v2 23 | with: 24 | endpoint: builders 25 | - 26 | name: Login to Docker Hub 27 | uses: docker/login-action@v2 28 | with: 29 | username: ${{ secrets.DOCKERHUB_USERNAME }} 30 | password: ${{ secrets.DOCKERHUB_TOKEN }} 31 | - 32 | name: Build and push 33 | uses: docker/build-push-action@v4 34 | with: 35 | context: . 36 | platforms: linux/amd64,linux/arm64 37 | push: true 38 | tags: whydesd/nyabot:dev 39 | harbor: 40 | runs-on: ubuntu-20.04 41 | steps: 42 | - name: Checkout Repository 43 | uses: actions/checkout@v3 44 | - name: Set up QEMU 45 | uses: docker/setup-qemu-action@v2 46 | - name: Set up Docker Context for Buildx 47 | id: buildx-context 48 | run: | 49 | docker context create builders 50 | - name: Set up Docker Buildx 51 | uses: docker/setup-buildx-action@v2 52 | with: 53 | endpoint: builders 54 | - name: Login to Harbor 55 | uses: docker/login-action@v2 56 | with: 57 | registry: registry.infra.elyart.cn 58 | username: ${{ secrets.HARBOR_UNA }} 59 | password: ${{ secrets.HARBOR_PWD }} 60 | - name: Build and push 61 | uses: docker/build-push-action@v4 62 | with: 63 | context: . 64 | platforms: linux/amd64,linux/arm64 65 | push: true 66 | tags: registry.infra.elyart.cn/nyabot/nyabot-ce:dev -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | *.test 8 | *.out 9 | test.go 10 | NyaBot 11 | config.yaml 12 | go.work 13 | vendor 14 | plugins/* 15 | scripts/* 16 | !plugins/.gitkeep 17 | !scripts/.gitkeep 18 | database.db 19 | app.log 20 | dist 21 | .release-env -------------------------------------------------------------------------------- /.goreleaser.yaml: -------------------------------------------------------------------------------- 1 | builds: 2 | - id: darwin-amd64 3 | main: ./ 4 | binary: golang-cross 5 | goos: 6 | - darwin 7 | goarch: 8 | - amd64 9 | env: 10 | - CC=o64-clang 11 | - CXX=o64-clang++ 12 | flags: 13 | - -mod=readonly 14 | ldflags: 15 | - -s -w -X main.version={{.Version}} 16 | - id: darwin-arm64 17 | main: ./ 18 | binary: golang-cross 19 | goos: 20 | - darwin 21 | goarch: 22 | - arm64 23 | env: 24 | - CC=oa64-clang 25 | - CXX=oa64-clang++ 26 | flags: 27 | - -mod=readonly 28 | ldflags: 29 | - -s -w -X main.version={{.Version}} 30 | - id: linux-amd64 31 | main: ./ 32 | binary: golang-cross 33 | goos: 34 | - linux 35 | goarch: 36 | - amd64 37 | env: 38 | - CC=x86_64-linux-gnu-gcc 39 | - CXX=x86_64-linux-gnu-g++ 40 | flags: 41 | - -mod=readonly 42 | ldflags: 43 | - -s -w -X main.version={{.Version}} 44 | - id: linux-arm64 45 | main: ./ 46 | binary: golang-cross 47 | goos: 48 | - linux 49 | goarch: 50 | - arm64 51 | env: 52 | - CC=aarch64-linux-gnu-gcc 53 | - CXX=aarch64-linux-gnu-g++ 54 | flags: 55 | - -mod=readonly 56 | ldflags: 57 | - -s -w -X main.version={{.Version}} 58 | - id: windows-amd64 59 | main: ./ 60 | binary: golang-cross 61 | goos: 62 | - windows 63 | goarch: 64 | - amd64 65 | env: 66 | - CC=x86_64-w64-mingw32-gcc 67 | - CXX=x86_64-w64-mingw32-g++ 68 | flags: 69 | - -mod=readonly 70 | ldflags: 71 | - -s -w -X main.version={{.Version}} 72 | - id: windows-arm64 73 | main: ./ 74 | binary: golang-cross 75 | goos: 76 | - windows 77 | goarch: 78 | - arm64 79 | env: 80 | - CC=/llvm-mingw/bin/aarch64-w64-mingw32-gcc 81 | - CXX=/llvm-mingw/bin/aarch64-w64-mingw32-g++ 82 | flags: 83 | - -mod=readonly 84 | ldflags: 85 | - -s -w -X main.version={{.Version}} 86 | archives: 87 | - id: golang-cross 88 | builds: 89 | - darwin-amd64 90 | - darwin-arm64 91 | - linux-amd64 92 | - linux-arm64 93 | - windows-amd64 94 | - windows-arm64 95 | name_template: "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}" 96 | format: zip 97 | wrap_in_directory: true 98 | checksum: 99 | name_template: 'checksums.txt' 100 | snapshot: 101 | name_template: "{{ .Tag }}" 102 | changelog: 103 | sort: asc 104 | filters: 105 | exclude: 106 | - '^docs:' 107 | - '^test:' 108 | 109 | release: 110 | github: 111 | owner: Elyart-Network 112 | name: NyaBot 113 | prerelease: auto 114 | draft: false 115 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.20-alpine AS builder 2 | WORKDIR /app 3 | COPY . . 4 | RUN go mod download 5 | RUN go build -o NyaBot . 6 | 7 | FROM alpine:latest 8 | WORKDIR /app 9 | COPY --from=builder /app/NyaBot . 10 | ENV RUN_IN_DOCKER=1 11 | EXPOSE 3000 12 | CMD ["./NyaBot"] -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all build clean test check run docker help 2 | BIN_FILE=nyabot 3 | all: check build 4 | start: check build run 5 | build: 6 | @go build -o "${BIN_FILE}" 7 | clean: 8 | @go clean 9 | test: 10 | @go test 11 | check: 12 | @go fmt ./ 13 | @go vet ./ 14 | run: 15 | ./"${BIN_FILE}" 16 | docker: 17 | @docker build -t whydesd/nyabot:test . 18 | help: 19 | @echo "make 格式化go代码 并编译生成二进制文件" 20 | @echo "make start 格式化go代码 编译生成二进制文件 并运行" 21 | @echo "make build 编译go代码生成二进制文件" 22 | @echo "make clean 清理中间目标文件" 23 | @echo "make test 执行测试case" 24 | @echo "make check 格式化go代码" 25 | @echo "make run 直接运行程序" 26 | @echo "make docker 构建docker镜像" 27 | 28 | PACKAGE_NAME := github.com/Elyart-Network/NyaBot 29 | GOLANG_CROSS_VERSION ?= v1.20.5 30 | 31 | SYSROOT_DIR ?= sysroots 32 | SYSROOT_ARCHIVE ?= sysroots.tar.bz2 33 | 34 | .PHONY: sysroot-pack 35 | sysroot-pack: 36 | @tar cf - $(SYSROOT_DIR) -P | pv -s $[$(du -sk $(SYSROOT_DIR) | awk '{print $1}') * 1024] | pbzip2 > $(SYSROOT_ARCHIVE) 37 | 38 | .PHONY: sysroot-unpack 39 | sysroot-unpack: 40 | @pv $(SYSROOT_ARCHIVE) | pbzip2 -cd | tar -xf - 41 | 42 | .PHONY: release-dry-run 43 | release-dry-run: 44 | @docker run \ 45 | --rm \ 46 | -e CGO_ENABLED=1 \ 47 | -v /var/run/docker.sock:/var/run/docker.sock \ 48 | -v `pwd`:/go/src/$(PACKAGE_NAME) \ 49 | -v `pwd`/sysroot:/sysroot \ 50 | -w /go/src/$(PACKAGE_NAME) \ 51 | ghcr.io/goreleaser/goreleaser-cross:${GOLANG_CROSS_VERSION} \ 52 | --rm-dist --skip-validate --skip-publish 53 | 54 | .PHONY: release 55 | release: 56 | @if [ ! -f ".release-env" ]; then \ 57 | echo "\033[91m.release-env is required for release\033[0m";\ 58 | exit 1;\ 59 | fi 60 | docker run \ 61 | --rm \ 62 | -e CGO_ENABLED=1 \ 63 | --env-file .release-env \ 64 | -v /var/run/docker.sock:/var/run/docker.sock \ 65 | -v `pwd`:/go/src/$(PACKAGE_NAME) \ 66 | -v `pwd`/sysroot:/sysroot \ 67 | -w /go/src/$(PACKAGE_NAME) \ 68 | ghcr.io/goreleaser/goreleaser-cross:${GOLANG_CROSS_VERSION} \ 69 | release --rm-dist -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![NyaBot](https://socialify.git.ci/Elyart-Network/NyaBot/image?description=1&descriptionEditable=A%20ChatBot%20Framework%20based%20on%20GoLang&language=1&name=1&owner=1&theme=Auto) 2 | 3 | ### NyaBot v3 4 | 5 | ----- 6 | 7 | ![GitHub](https://img.shields.io/github/license/Elyart-Network/NyaBot?style=flat-square) ![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/Elyart-Network/NyaBot/commit-check.yml?label=check&style=flat-square) ![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/Elyart-Network/NyaBot/codeql.yml?label=security&style=flat-square) ![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/Elyart-Network/NyaBot/docker-dev.yml?label=image&style=flat-square) ![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/Elyart-Network/NyaBot/build-release.yml?label=build&style=flat-square) ![GitHub release (latest by date including pre-releases)](https://img.shields.io/github/v/release/Elyart-Network/NyaBot?include_prereleases&style=flat-square) 8 | 9 | - GoLang Version: 1.20+ 10 | 11 | ## GoCqHttp REST API 12 | 13 | - Go to [ApiFox](https://www.apifox.cn/apidoc/shared-2a26dd5d-8520-47f5-9080-3614b97009ec) 14 | 15 | ## NyaBot v3 Documents 16 | 17 | - [Click Here !](https://nyabot.elyart.org/) 18 | 19 | ## Support Us 20 | 21 | - Fix bugs and send PRs 22 | - Submit Issues 23 | - Star this project 24 | - Use this project 25 | - Submit some plugins 26 | 27 |
28 | This project is fully open source, and using Apache 2.0 License. 29 | In case our cookies show up on your doorstep one day, please accept it! 😉 30 |
31 | 32 | ## Contributors 33 | 34 | 35 | [![All Contributors](https://img.shields.io/badge/all_contributors-2-orange.svg?style=flat-square)](#contributors-) 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 |
BaiYi
BaiYi

💻 🐛 🚇 🎨 📆
isNagatoYuki
isNagatoYuki

🐛 💻
49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | ## LICENSE 63 | 64 | Apache License 2.0 65 | 66 | ## Thanks 67 | 68 | #### [JetBrains](https://www.jetbrains.com/?from=NyaBot) for providing us with free licenses for their awesome IDEs. 69 | 70 | ![JetBrains](https://www.jetbrains.com/company/brand/img/jetbrains_logo.png) 71 | -------------------------------------------------------------------------------- /app.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // import a plugin by simply add a blank import. 4 | import ( 5 | "github.com/Elyart-Network/NyaBot/config" 6 | _ "github.com/Elyart-Network/NyaBot/data" // Prepare Data Sources 7 | _ "github.com/Elyart-Network/NyaBot/internal/logging" // Logging Plugin 8 | _ "github.com/Elyart-Network/NyaBot/logger" // Prepare Logger 9 | "github.com/Elyart-Network/NyaBot/server" 10 | // _ "github.com/Elyart-Network/NyaBot/examples/plugin" // Example Plugin 11 | _ "github.com/Elyart-Network/NyaBot/internal/lua" // Lua Plugin 12 | // _ "github.com/Elyart-Network/NyaBot/internal/grpc" // gRPC Plugin 13 | // _ "github.com/Elyart-Network/NyaBot/internal/javascript" // JavaScript Plugin 14 | ) 15 | 16 | func main() { 17 | config.EnvInit() // Initialize environment variables 18 | server.Start() // Start server (framework) 19 | } 20 | -------------------------------------------------------------------------------- /config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "github.com/spf13/viper" 5 | "log" 6 | ) 7 | 8 | func init() { 9 | // Read global config 10 | viper.SetConfigFile("config.yaml") 11 | viper.SetDefault("Server", serverDef) 12 | viper.SetDefault("Mirai", miraiDef) 13 | viper.SetDefault("GoCqHttp", goCqHttpDef) 14 | viper.SetDefault("Database", databaseDef) 15 | viper.SetDefault("Logging", loggingDef) 16 | viper.SetDefault("Cache", cacheDef) 17 | viper.SetDefault("Search", searchDef) 18 | viper.SetDefault("Plugin", pluginDef) 19 | conf := &config{} 20 | if err := viper.ReadInConfig(); err != nil { 21 | log.Println("Can't read config, trying to modify!") 22 | if err := viper.WriteConfig(); err != nil { 23 | log.Fatal("[Config] Error writing config: ", err) 24 | } 25 | } 26 | if err := viper.Unmarshal(conf); err != nil { 27 | log.Fatal(err) 28 | } 29 | } 30 | 31 | func Get(key string) any { 32 | viper.SetConfigFile("config.yaml") 33 | if err := viper.ReadInConfig(); err != nil { 34 | log.Fatal("[Config] Error reading config: ", err) 35 | } 36 | return viper.Get(key) 37 | } 38 | 39 | func Set(key string, value any) { 40 | viper.SetConfigFile("config.yaml") 41 | if err := viper.ReadInConfig(); err != nil { 42 | log.Fatal("[Config] Error reading config: ", err) 43 | } 44 | viper.Set(key, value) 45 | } 46 | -------------------------------------------------------------------------------- /config/default.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | var serverDef = server{ 4 | ListenPort: "3000", 5 | RpcPort: "3001", 6 | DebugMode: false, 7 | FileLogger: false, 8 | } 9 | 10 | var miraiDef = mirai{ 11 | Enable: false, 12 | } 13 | 14 | var goCqHttpDef = goCqHttp{ 15 | Enable: false, 16 | HostUrl: "http://127.0.0.1:5700", 17 | Delay: 3000, 18 | EnableWs: false, 19 | } 20 | 21 | var databaseDef = database{ 22 | Type: "sqlite", 23 | } 24 | 25 | var loggingDef = logging{ 26 | External: false, 27 | MongoUri: "mongodb://", 28 | CacheNum: 80, 29 | InternalLog: false, 30 | } 31 | 32 | var cacheDef = cache{ 33 | External: false, 34 | } 35 | 36 | var searchDef = search{ 37 | Enable: false, 38 | } 39 | 40 | var pluginDef = plugin{ 41 | LuaEnable: true, 42 | LuaScriptDir: "scripts", 43 | LuaSandbox: false, 44 | } 45 | -------------------------------------------------------------------------------- /config/env.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "github.com/joho/godotenv" 5 | "log" 6 | "os" 7 | "strconv" 8 | "strings" 9 | ) 10 | 11 | func GetEnv(Key string) string { 12 | _ = godotenv.Load() 13 | return os.Getenv(Key) 14 | } 15 | 16 | func SetEnvConf(ConfKey string, ConfSub string) { 17 | var Config = []string{ConfKey, ConfSub} 18 | var EnvKey = strings.Join(Config, "_") 19 | env := GetEnv(EnvKey) 20 | var orig = Get(ConfKey + "." + ConfSub) 21 | if env != "" { 22 | switch orig.(type) { 23 | case string: 24 | Set(ConfKey, env) 25 | case int: 26 | conv, err := strconv.Atoi(env) 27 | if err != nil { 28 | log.Panic("[Config] Error converting string to int: ", err) 29 | } 30 | Set(ConfKey, conv) 31 | case bool: 32 | switch env { 33 | case "true": 34 | Set(ConfKey, true) 35 | case "false": 36 | Set(ConfKey, false) 37 | } 38 | case []string: 39 | trim := strings.TrimSpace(env) 40 | trim = strings.TrimPrefix(trim, "[") 41 | trim = strings.TrimSuffix(trim, "]") 42 | var envArray []string 43 | for _, v := range strings.Split(trim, ",") { 44 | trimSub := strings.TrimPrefix(v, "\"") 45 | trimSub = strings.TrimSuffix(trimSub, "\"") 46 | envArray = append(envArray, trimSub) 47 | } 48 | Set(ConfKey, envArray) 49 | } 50 | } 51 | } 52 | 53 | func EnvInit() { 54 | var dict = map[string][]string{ 55 | "server": {"listen_port", "rpc_port", "debug_mode", "file_logger"}, 56 | "mirai": {"enable"}, 57 | "gocqhttp": {"enable", "host_url", "delay", "enable_ws"}, 58 | "database": {"type", "host", "name", "username", "password"}, 59 | "logging": {"external", "mongo_uri", "mongo_db", "cache_num", "internal_log"}, 60 | "cache": {"external", "hosts", "master", "username", "password"}, 61 | "search": {"enable", "host", "index_name", "username", "password"}, 62 | "plugin": {"lua_enable", "lua_script_dir", "lua_sandbox"}, 63 | } 64 | for key, value := range dict { 65 | for _, sub := range value { 66 | SetEnvConf(key, sub) 67 | } 68 | } 69 | } 70 | 71 | func TZ() string { 72 | tz := GetEnv("TZ") 73 | if tz == "" { 74 | return "Asia/Shanghai" 75 | } 76 | return tz 77 | } 78 | -------------------------------------------------------------------------------- /config/types.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | type config struct { 4 | Server server `yaml:"server"` 5 | Mirai mirai `yaml:"mirai"` 6 | GoCqHttp goCqHttp `yaml:"gocqhttp"` 7 | Database database `yaml:"database"` 8 | Logging logging `yaml:"logging"` 9 | Cache cache `yaml:"cache"` 10 | Search search `yaml:"search"` 11 | Plugin plugin `yaml:"plugin"` 12 | } 13 | 14 | type server struct { 15 | ListenPort string `yaml:"listen_port"` 16 | RpcPort string `yaml:"rpc_port"` 17 | DebugMode bool `yaml:"debug_mode"` 18 | FileLogger bool `yaml:"file_logger"` 19 | } 20 | 21 | type mirai struct { 22 | Enable bool `yaml:"enable"` 23 | } 24 | 25 | type goCqHttp struct { 26 | Enable bool `yaml:"enable"` 27 | HostUrl string `yaml:"host_url"` 28 | Delay int `yaml:"delay"` 29 | EnableWs bool `yaml:"enable_ws"` 30 | } 31 | 32 | // SQLite or MySQL or PostgreSQL 33 | type database struct { 34 | Type string `yaml:"type"` 35 | Host string `yaml:"host"` 36 | Name string `yaml:"name"` 37 | Username string `yaml:"username"` 38 | Password string `yaml:"password"` 39 | } 40 | 41 | // MongoDB 42 | type logging struct { 43 | External bool `yaml:"external"` 44 | MongoUri string `yaml:"mongo_uri"` 45 | MongoDB string `yaml:"mongo_db"` 46 | CacheNum int `yaml:"cache_num"` 47 | InternalLog bool `yaml:"internal_log"` 48 | } 49 | 50 | // InMem or Redis 51 | type cache struct { 52 | External bool `yaml:"external"` 53 | Hosts []string `yaml:"hosts"` 54 | Master string `yaml:"master"` 55 | Username string `yaml:"username"` 56 | Password string `yaml:"password"` 57 | } 58 | 59 | // Elasticsearch 60 | type search struct { 61 | Enable bool `yaml:"enable"` 62 | Host string `yaml:"host"` 63 | IndexName string `yaml:"index_name"` 64 | Username string `yaml:"username"` 65 | Password string `yaml:"password"` 66 | } 67 | 68 | // Plugins 69 | type plugin struct { 70 | LuaEnable bool `yaml:"lua_enable"` 71 | LuaScriptDir string `yaml:"lua_script_dir"` 72 | LuaSandbox bool `yaml:"lua_sandbox"` 73 | } 74 | -------------------------------------------------------------------------------- /data/actions/handler.go: -------------------------------------------------------------------------------- 1 | package actions 2 | 3 | import ( 4 | "github.com/Elyart-Network/NyaBot/data/drivers" 5 | "gorm.io/gorm" 6 | ) 7 | 8 | var handler Handler 9 | 10 | type Handler struct { 11 | DB *gorm.DB 12 | Mongo *drivers.MongoClient 13 | Redis *drivers.RedisClient 14 | } 15 | 16 | func New(h Handler) { 17 | handler = h 18 | } 19 | -------------------------------------------------------------------------------- /data/actions/logging.go: -------------------------------------------------------------------------------- 1 | package actions 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "github.com/Elyart-Network/NyaBot/config" 7 | "github.com/Elyart-Network/NyaBot/data/models" 8 | log "github.com/sirupsen/logrus" 9 | ) 10 | 11 | type Logging struct{} 12 | 13 | func (l *Logging) Cache(ctx context.Context, collection string, content any) { 14 | // Connect to Cache and insert message 15 | cacheNum := config.Get("logging.cache_num").(int) 16 | externalCache := config.Get("cache.external").(bool) 17 | if cacheNum > 0 { 18 | switch externalCache { 19 | case true: 20 | // Connect to Redis and insert message 21 | r := handler.Redis 22 | clen := r.LLen(ctx, collection) 23 | if clen.Val() >= int64(cacheNum) { 24 | // Remove oldest message 25 | r.LPopCount(ctx, collection, 1) 26 | } 27 | r.RPush(ctx, collection, content) 28 | err := r.Close() 29 | if err != nil { 30 | log.Warning("[Redis] Failed to disconnect from Redis: ", err) 31 | } 32 | log.Debug("[Redis] Pushed message to cache.") 33 | case false: 34 | // TODO 35 | } 36 | } 37 | } 38 | 39 | func (l *Logging) Insert(ctx context.Context, collection string, content any) { 40 | // Connect to MongoDB and insert message 41 | enableMDB := config.Get("logging.external").(bool) 42 | if enableMDB { 43 | m := handler.Mongo 44 | _, err := m.Database("NyaBot").Collection(collection).InsertOne(ctx, content) 45 | err = m.Disconnect(ctx) 46 | if err != nil { 47 | log.Warning("[MongoDB] Failed to disconnect from MongoDB: ", err) 48 | } 49 | log.Debug("[MongoDB] Inserted message to doc database.") 50 | } else { 51 | // Return when internal_log is not enabled 52 | internalLog := config.Get("logging.internal_log").(bool) 53 | if !internalLog { 54 | return 55 | } 56 | 57 | // Save Chat log to Database 58 | contentStr, err := json.Marshal(content) 59 | if err != nil { 60 | log.Warning("[Logging] Failed to Marshal content: ", err) 61 | } 62 | data := models.Logging{ 63 | Collection: collection, 64 | Content: string(contentStr), 65 | } 66 | handler.DB.Save(&data) 67 | log.Debug("[InternalLog] Inserted message to database.") 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /data/actions/plugin.go: -------------------------------------------------------------------------------- 1 | package actions 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/Elyart-Network/NyaBot/data/models" 6 | log "github.com/sirupsen/logrus" 7 | ) 8 | 9 | type Plugin struct{} 10 | 11 | func (p *Plugin) SaveConfig(UID int64, PName string, PType string, PConfig any, PAdd string) error { 12 | cfg, _ := json.Marshal(PConfig) 13 | data := models.Plugin{ 14 | ID: UID, 15 | Name: PName, 16 | Type: PType, 17 | Config: string(cfg), 18 | Addition: PAdd, 19 | } 20 | err := handler.DB.Save(&data).Error 21 | log.Debug("[DBAct](SaveConfig) Saved! @PName:", PName, " @PType:", PType, " @PConfig", PConfig, " @PAdd:", PAdd) 22 | return err 23 | } 24 | 25 | func (p *Plugin) GetConfig(PName string, PType string) (models.Plugin, error) { 26 | data := models.Plugin{Name: PName, Type: PType} 27 | err := handler.DB.First(&data).Error 28 | log.Debug("[DBAct](GetConfig) Get Config. @PName:", PName, " @Type:", data.Type, " @Config:", data.Config, " @Addition:", data.Addition) 29 | return data, err 30 | } 31 | 32 | func (p *Plugin) DeleteConfig(PName string, PType string) error { 33 | data := models.Plugin{Name: PName, Type: PType} 34 | err := handler.DB.Where("name = ? AND type = ?", PName, PType).Delete(&data).Error 35 | log.Debug("[DBAct](DeleteConfig) Deleted! @PName:", PName) 36 | return err 37 | } 38 | -------------------------------------------------------------------------------- /data/drivers/memory.go: -------------------------------------------------------------------------------- 1 | package drivers 2 | -------------------------------------------------------------------------------- /data/drivers/mongo.go: -------------------------------------------------------------------------------- 1 | package drivers 2 | 3 | import ( 4 | "context" 5 | "go.mongodb.org/mongo-driver/mongo" 6 | "go.mongodb.org/mongo-driver/mongo/options" 7 | ) 8 | 9 | func MongoDB(dsn MongoDSN) (*MongoClient, error) { 10 | // Connect to MongoDB 11 | ctx := context.Background() 12 | conn, err := mongo.Connect(ctx, options.Client().ApplyURI(dsn.MongoUri)) 13 | err = conn.Ping(ctx, nil) 14 | return &MongoClient{conn}, err 15 | } 16 | -------------------------------------------------------------------------------- /data/drivers/mysql.go: -------------------------------------------------------------------------------- 1 | package drivers 2 | 3 | import ( 4 | "gorm.io/driver/mysql" 5 | "gorm.io/gorm" 6 | ) 7 | 8 | func Mysql(dsn ExternalDSN) (*DBClient, error) { 9 | conn := dsn.Username + ":" + dsn.Password + "@tcp(" + dsn.Host + ")/" + dsn.Name + "?charset=utf8mb4&parseTime=True&loc=Local" 10 | db, err := gorm.Open(mysql.Open(conn), &gorm.Config{}) 11 | return &DBClient{db}, err 12 | } 13 | -------------------------------------------------------------------------------- /data/drivers/postgres.go: -------------------------------------------------------------------------------- 1 | package drivers 2 | 3 | import ( 4 | "github.com/Elyart-Network/NyaBot/config" 5 | "gorm.io/driver/postgres" 6 | "gorm.io/gorm" 7 | "strings" 8 | ) 9 | 10 | func SplitHostPort(url string) (host, port string) { 11 | if !strings.Contains(url, ":") { 12 | return url, "5432" 13 | } 14 | split := strings.Split(url, ":") 15 | return split[0], split[1] 16 | } 17 | 18 | func Postgres(dsn ExternalDSN) (*DBClient, error) { 19 | host, port := SplitHostPort(dsn.Host) 20 | conn := "host=" + host + " user=" + dsn.Username + " password=" + dsn.Password + " dbname=" + dsn.Name + " port=" + port + " sslmode=disable TimeZone=" + config.TZ() 21 | db, err := gorm.Open(postgres.Open(conn), &gorm.Config{}) 22 | return &DBClient{db}, err 23 | } 24 | -------------------------------------------------------------------------------- /data/drivers/redis.go: -------------------------------------------------------------------------------- 1 | package drivers 2 | 3 | import ( 4 | "context" 5 | "github.com/redis/go-redis/v9" 6 | ) 7 | 8 | func Redis(dsn RedisDSN) (*RedisClient, error) { 9 | // Connect to Redis 10 | rdb := redis.NewUniversalClient(&redis.UniversalOptions{ 11 | Addrs: dsn.Hosts, 12 | MasterName: dsn.Master, 13 | Username: dsn.Username, 14 | Password: dsn.Password, 15 | DB: dsn.DB, 16 | }) 17 | ctx := context.Background() 18 | // Ping Redis 19 | _, err := rdb.Ping(ctx).Result() 20 | return &RedisClient{rdb}, err 21 | } 22 | -------------------------------------------------------------------------------- /data/drivers/sqlite.go: -------------------------------------------------------------------------------- 1 | package drivers 2 | 3 | import ( 4 | "gorm.io/driver/sqlite" 5 | "gorm.io/gorm" 6 | ) 7 | 8 | func Sqlite(dsn SqliteDSN) (*DBClient, error) { 9 | db, err := gorm.Open(sqlite.Open(dsn.DB), &gorm.Config{}) 10 | return &DBClient{db}, err 11 | } 12 | -------------------------------------------------------------------------------- /data/drivers/types.go: -------------------------------------------------------------------------------- 1 | package drivers 2 | 3 | import ( 4 | "github.com/redis/go-redis/v9" 5 | "go.mongodb.org/mongo-driver/mongo" 6 | "gorm.io/gorm" 7 | ) 8 | 9 | type SqliteDSN struct { 10 | DB string 11 | } 12 | 13 | type ExternalDSN struct { 14 | Host string 15 | Name string 16 | Username string 17 | Password string 18 | } 19 | 20 | type RedisDSN struct { 21 | Hosts []string 22 | Master string 23 | Username string 24 | Password string 25 | DB int 26 | } 27 | 28 | type MongoDSN struct { 29 | MongoUri string 30 | } 31 | 32 | type MongoClient struct { 33 | *mongo.Client 34 | } 35 | 36 | type RedisClient struct { 37 | redis.UniversalClient 38 | } 39 | 40 | type DBClient struct { 41 | *gorm.DB 42 | } 43 | -------------------------------------------------------------------------------- /data/initializer.go: -------------------------------------------------------------------------------- 1 | package data 2 | 3 | import ( 4 | "github.com/Elyart-Network/NyaBot/config" 5 | "github.com/Elyart-Network/NyaBot/data/actions" 6 | "github.com/Elyart-Network/NyaBot/data/drivers" 7 | "github.com/Elyart-Network/NyaBot/data/models" 8 | log "github.com/sirupsen/logrus" 9 | ) 10 | 11 | func init() { 12 | handler := actions.Handler{} 13 | var ( 14 | db *drivers.DBClient 15 | err error 16 | ) 17 | 18 | // Init database 19 | dbType := config.Get("database.type").(string) 20 | exDSN := drivers.ExternalDSN{ 21 | Host: config.Get("database.host").(string), 22 | Name: config.Get("database.name").(string), 23 | Username: config.Get("database.username").(string), 24 | Password: config.Get("database.password").(string), 25 | } 26 | switch dbType { 27 | default: 28 | liteDSN := drivers.SqliteDSN{DB: "database.db"} 29 | db, err = drivers.Sqlite(liteDSN) 30 | case "mysql": 31 | db, err = drivers.Mysql(exDSN) 32 | case "postgres": 33 | db, err = drivers.Postgres(exDSN) 34 | } 35 | if err != nil { 36 | log.Fatal("["+dbType+"] Error connecting to database: ", err) 37 | } 38 | handler.DB = db.DB 39 | 40 | // Init redis 41 | externalCache := config.Get("cache.external").(bool) 42 | if externalCache { 43 | // Convert []interface{} to []string 44 | addrSlice := config.Get("cache.hosts").([]interface{}) 45 | var rdbAddress []string 46 | for _, v := range addrSlice { 47 | rdbAddress = append(rdbAddress, v.(string)) 48 | } 49 | dsn := drivers.RedisDSN{ 50 | Hosts: rdbAddress, 51 | Master: config.Get("cache.master").(string), 52 | Username: config.Get("cache.username").(string), 53 | Password: config.Get("cache.password").(string), 54 | DB: 0, 55 | } 56 | conn, err := drivers.Redis(dsn) 57 | if err != nil { 58 | log.Fatal("[Redis] Error connecting to Redis: ", err) 59 | } 60 | handler.Redis = conn 61 | } 62 | 63 | // Init MongoDB 64 | externalLogging := config.Get("logging.external").(bool) 65 | if externalLogging { 66 | dsn := drivers.MongoDSN{MongoUri: config.Get("logging.mongo_uri").(string)} 67 | conn, err := drivers.MongoDB(dsn) 68 | if err != nil { 69 | log.Fatal("[MongoDB] Error connecting to MongoDB: ", err) 70 | } 71 | handler.Mongo = conn 72 | } 73 | 74 | // Initialize 75 | err = handler.DB.AutoMigrate(&models.Plugin{}, &models.Logging{}) 76 | if err != nil { 77 | log.Error("[Database] Error migrating database: ", err) 78 | } 79 | actions.New(handler) 80 | log.Debug("[Database] Data sources initialized!") 81 | } 82 | -------------------------------------------------------------------------------- /data/models/database.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | type Plugin struct { 4 | ID int64 `json:"id" gorm:"primaryKey;autoIncrement;not null;unique"` 5 | Name string `json:"name" gorm:"not null;unique"` 6 | Type string `json:"type" gorm:"not null"` 7 | Config string `json:"config" gorm:"not null"` 8 | Addition string `json:"addition" gorm:"default:null"` 9 | } 10 | 11 | type Logging struct { 12 | ID int64 `json:"id" gorm:"primaryKey;autoIncrement;not null;unique"` 13 | Collection string `json:"collection" gorm:"not null"` 14 | Content string `json:"content" gorm:"not null"` 15 | } 16 | -------------------------------------------------------------------------------- /examples/example.lua: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SNENET/NyaBot/f0a7c6e76114660ac1628fe9e023efac1121bcbe/examples/example.lua -------------------------------------------------------------------------------- /examples/plugin/gocqhttp.go: -------------------------------------------------------------------------------- 1 | package plugin 2 | 3 | import ( 4 | "github.com/Elyart-Network/NyaBot/pkg/gocqhttp/callback" 5 | "github.com/Elyart-Network/NyaBot/pkg/plugin" 6 | "log" 7 | ) 8 | 9 | // CqPlugin a struct for all functions below. 10 | type CqPlugin struct{} 11 | 12 | // Info set plugin info, `Name` has to be unique! 13 | func (p *CqPlugin) Info() plugin.InfoStruct { 14 | return plugin.InfoStruct{ 15 | Name: "cq_example", 16 | Version: "", 17 | Author: "", 18 | Description: "", 19 | License: "", 20 | Homepage: "", 21 | Repository: "", 22 | Type: "GoCqHttp", 23 | } 24 | } 25 | 26 | // Message process message event from callback. (required) 27 | func (p *CqPlugin) Message(ctx callback.Full) { 28 | log.Println("Message") 29 | } 30 | 31 | // Request process request event from callback. (required) 32 | func (p *CqPlugin) Request(ctx callback.Full) { 33 | log.Println("Request") 34 | } 35 | 36 | // Notice process notice event from callback. (required) 37 | func (p *CqPlugin) Notice(ctx callback.Full) { 38 | log.Println("Notice") 39 | } 40 | 41 | // MetaEvent process meta event from callback. (required) 42 | func (p *CqPlugin) MetaEvent(ctx callback.Full) { 43 | log.Println("MetaEvent") 44 | } 45 | 46 | // init register plugin and depends to plugin manager (frame). 47 | func init() { 48 | plugin.CqRegister(&CqPlugin{}) 49 | } 50 | -------------------------------------------------------------------------------- /examples/plugin/webhook.go: -------------------------------------------------------------------------------- 1 | package plugin 2 | 3 | import ( 4 | "github.com/Elyart-Network/NyaBot/pkg/plugin" 5 | "github.com/Elyart-Network/NyaBot/pkg/webhook" 6 | ) 7 | 8 | // WhPlugin a struct for all functions below. 9 | type WhPlugin struct{} 10 | 11 | // Info set plugin info, `Name` has to be unique! 12 | func (p *WhPlugin) Info() plugin.InfoStruct { 13 | return plugin.InfoStruct{ 14 | Name: "wh_example", 15 | Version: "", 16 | Author: "", 17 | Description: "", 18 | License: "", 19 | Homepage: "", 20 | Repository: "", 21 | Type: "Webhook", 22 | } 23 | } 24 | 25 | // Receive process webhook data from callback. (required) 26 | func (p *WhPlugin) Receive(callback webhook.Data) { 27 | 28 | } 29 | 30 | // init register plugin and depends to plugin manager (frame). 31 | func init() { 32 | plugin.WhRegister(&WhPlugin{}) 33 | } 34 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/Elyart-Network/NyaBot 2 | 3 | go 1.20 4 | 5 | replace layeh.com/gopher-luar v1.0.10 => github.com/layeh/gopher-luar v1.0.10 6 | 7 | require ( 8 | github.com/gin-gonic/gin v1.9.1 9 | github.com/gorilla/websocket v1.5.0 10 | github.com/joho/godotenv v1.5.1 11 | github.com/redis/go-redis/v9 v9.0.4 12 | github.com/shirou/gopsutil/v3 v3.23.3 13 | github.com/sirupsen/logrus v1.9.2 14 | github.com/spf13/viper v1.15.0 15 | github.com/yuin/gopher-lua v1.1.0 16 | go.mongodb.org/mongo-driver v1.11.6 17 | golang.org/x/sync v0.2.0 18 | google.golang.org/grpc v1.55.0 19 | gopkg.in/ini.v1 v1.67.0 20 | gorm.io/driver/mysql v1.5.1 21 | gorm.io/driver/postgres v1.5.2 22 | gorm.io/driver/sqlite v1.5.1 23 | gorm.io/gorm v1.25.1 24 | layeh.com/gopher-luar v1.0.10 25 | ) 26 | 27 | require ( 28 | github.com/bytedance/sonic v1.9.1 // indirect 29 | github.com/cespare/xxhash/v2 v2.2.0 // indirect 30 | github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect 31 | github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect 32 | github.com/fsnotify/fsnotify v1.6.0 // indirect 33 | github.com/gabriel-vasile/mimetype v1.4.2 // indirect 34 | github.com/gin-contrib/sse v0.1.0 // indirect 35 | github.com/go-ole/go-ole v1.2.6 // indirect 36 | github.com/go-playground/locales v0.14.1 // indirect 37 | github.com/go-playground/universal-translator v0.18.1 // indirect 38 | github.com/go-playground/validator/v10 v10.14.0 // indirect 39 | github.com/go-sql-driver/mysql v1.7.1 // indirect 40 | github.com/goccy/go-json v0.10.2 // indirect 41 | github.com/golang/protobuf v1.5.3 // indirect 42 | github.com/golang/snappy v0.0.1 // indirect 43 | github.com/hashicorp/hcl v1.0.0 // indirect 44 | github.com/jackc/pgpassfile v1.0.0 // indirect 45 | github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect 46 | github.com/jackc/pgx/v5 v5.3.1 // indirect 47 | github.com/jinzhu/inflection v1.0.0 // indirect 48 | github.com/jinzhu/now v1.1.5 // indirect 49 | github.com/json-iterator/go v1.1.12 // indirect 50 | github.com/klauspost/compress v1.13.6 // indirect 51 | github.com/klauspost/cpuid/v2 v2.2.4 // indirect 52 | github.com/leodido/go-urn v1.2.4 // indirect 53 | github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect 54 | github.com/magiconair/properties v1.8.7 // indirect 55 | github.com/mattn/go-isatty v0.0.19 // indirect 56 | github.com/mattn/go-sqlite3 v1.14.17 // indirect 57 | github.com/mitchellh/mapstructure v1.5.0 // indirect 58 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 59 | github.com/modern-go/reflect2 v1.0.2 // indirect 60 | github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect 61 | github.com/pelletier/go-toml/v2 v2.0.8 // indirect 62 | github.com/pkg/errors v0.9.1 // indirect 63 | github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect 64 | github.com/shoenig/go-m1cpu v0.1.4 // indirect 65 | github.com/spf13/afero v1.9.3 // indirect 66 | github.com/spf13/cast v1.5.0 // indirect 67 | github.com/spf13/jwalterweatherman v1.1.0 // indirect 68 | github.com/spf13/pflag v1.0.5 // indirect 69 | github.com/subosito/gotenv v1.4.2 // indirect 70 | github.com/tklauser/go-sysconf v0.3.11 // indirect 71 | github.com/tklauser/numcpus v0.6.0 // indirect 72 | github.com/twitchyliquid64/golang-asm v0.15.1 // indirect 73 | github.com/ugorji/go/codec v1.2.11 // indirect 74 | github.com/xdg-go/pbkdf2 v1.0.0 // indirect 75 | github.com/xdg-go/scram v1.1.1 // indirect 76 | github.com/xdg-go/stringprep v1.0.3 // indirect 77 | github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect 78 | github.com/yusufpapurcu/wmi v1.2.2 // indirect 79 | golang.org/x/arch v0.3.0 // indirect 80 | golang.org/x/crypto v0.9.0 // indirect 81 | golang.org/x/net v0.10.0 // indirect 82 | golang.org/x/sys v0.8.0 // indirect 83 | golang.org/x/text v0.9.0 // indirect 84 | google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect 85 | google.golang.org/protobuf v1.30.0 // indirect 86 | gopkg.in/yaml.v3 v3.0.1 // indirect 87 | ) 88 | -------------------------------------------------------------------------------- /internal/grpc/gocqhttp.go: -------------------------------------------------------------------------------- 1 | package grpc 2 | 3 | import ( 4 | "github.com/Elyart-Network/NyaBot/pkg/gocqhttp/callback" 5 | "github.com/Elyart-Network/NyaBot/pkg/plugin" 6 | "log" 7 | ) 8 | 9 | // Plugin a struct for all functions below. 10 | type Plugin struct{} 11 | 12 | // Info set plugin info, `Name` has to be unique! 13 | func (p *Plugin) Info() plugin.InfoStruct { 14 | return plugin.InfoStruct{ 15 | Name: "cq_internal_grpc", 16 | Version: "", 17 | Author: "", 18 | Description: "", 19 | License: "", 20 | Homepage: "", 21 | Repository: "", 22 | Type: "GoCqHttp", 23 | } 24 | } 25 | 26 | // Message process message event from callback. (required) 27 | func (p *Plugin) Message(callback callback.Full) { 28 | log.Println("Message") 29 | } 30 | 31 | // Request process request event from callback. (required) 32 | func (p *Plugin) Request(callback callback.Full) { 33 | log.Println("Request") 34 | } 35 | 36 | // Notice process notice event from callback. (required) 37 | func (p *Plugin) Notice(callback callback.Full) { 38 | log.Println("Notice") 39 | } 40 | 41 | // MetaEvent process meta event from callback. (required) 42 | func (p *Plugin) MetaEvent(callback callback.Full) { 43 | log.Println("MetaEvent") 44 | } 45 | 46 | // init register plugin and depends to plugin manager (frame). 47 | func init() { 48 | plugin.CqRegister(&Plugin{}) 49 | } 50 | -------------------------------------------------------------------------------- /internal/javascript/gocqhttp.go: -------------------------------------------------------------------------------- 1 | package javascript 2 | 3 | import ( 4 | "github.com/Elyart-Network/NyaBot/pkg/gocqhttp/callback" 5 | "github.com/Elyart-Network/NyaBot/pkg/plugin" 6 | "log" 7 | ) 8 | 9 | // Plugin a struct for all functions below. 10 | type Plugin struct{} 11 | 12 | // Info set plugin info, `Name` has to be unique! 13 | func (p *Plugin) Info() plugin.InfoStruct { 14 | return plugin.InfoStruct{ 15 | Name: "cq_internal_javascript", 16 | Version: "", 17 | Author: "", 18 | Description: "", 19 | License: "", 20 | Homepage: "", 21 | Repository: "", 22 | Type: "GoCqHttp", 23 | } 24 | } 25 | 26 | // Message process message event from callback. (required) 27 | func (p *Plugin) Message(callback callback.Full) { 28 | log.Println("Message") 29 | } 30 | 31 | // Request process request event from callback. (required) 32 | func (p *Plugin) Request(callback callback.Full) { 33 | log.Println("Request") 34 | } 35 | 36 | // Notice process notice event from callback. (required) 37 | func (p *Plugin) Notice(callback callback.Full) { 38 | log.Println("Notice") 39 | } 40 | 41 | // MetaEvent process meta event from callback. (required) 42 | func (p *Plugin) MetaEvent(callback callback.Full) { 43 | log.Println("MetaEvent") 44 | } 45 | 46 | // init register plugin and depends to plugin manager (frame). 47 | func init() { 48 | plugin.CqRegister(&Plugin{}) 49 | } 50 | -------------------------------------------------------------------------------- /internal/logging/gocqhttp.go: -------------------------------------------------------------------------------- 1 | package lua 2 | 3 | import ( 4 | "github.com/Elyart-Network/NyaBot/internal/logging/gocqhttp" 5 | "github.com/Elyart-Network/NyaBot/pkg/gocqhttp/callback" 6 | "github.com/Elyart-Network/NyaBot/pkg/plugin" 7 | ) 8 | 9 | // CqPlugin a struct for all functions below. 10 | type CqPlugin struct{} 11 | 12 | // Info set plugin info, `Name` has to be unique! 13 | func (p *CqPlugin) Info() plugin.InfoStruct { 14 | return plugin.InfoStruct{ 15 | Name: "cq_internal_logging", 16 | Version: "", 17 | Author: "", 18 | Description: "", 19 | License: "", 20 | Homepage: "", 21 | Repository: "", 22 | Type: "GoCqHttp", 23 | } 24 | } 25 | 26 | // Message process message event from callback. (required) 27 | func (p *CqPlugin) Message(ctx callback.Full) { 28 | gocqhttp.Message(ctx) 29 | } 30 | 31 | // Request process request event from callback. (required) 32 | func (p *CqPlugin) Request(ctx callback.Full) {} 33 | 34 | // Notice process notice event from callback. (required) 35 | func (p *CqPlugin) Notice(ctx callback.Full) {} 36 | 37 | // MetaEvent process meta event from callback. (required) 38 | func (p *CqPlugin) MetaEvent(ctx callback.Full) {} 39 | 40 | // init register plugin and depends to plugin manager (frame). 41 | func init() { 42 | plugin.CqRegister(&CqPlugin{}) 43 | } 44 | -------------------------------------------------------------------------------- /internal/logging/gocqhttp/message.go: -------------------------------------------------------------------------------- 1 | package gocqhttp 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "github.com/Elyart-Network/NyaBot/data/actions" 7 | "github.com/Elyart-Network/NyaBot/pkg/gocqhttp/callback" 8 | "strconv" 9 | ) 10 | 11 | func Message(ctx callback.Full) { 12 | // Create message object 13 | sender := Sender{ 14 | UserIdentity: strconv.FormatInt(ctx.Sender.UserID, 10), 15 | UserCard: ctx.Sender.Card, 16 | UserNick: ctx.Sender.Nickname, 17 | } 18 | msg := MessageData{ 19 | Sender: sender, 20 | Content: ctx.MessageData, 21 | MessageID: ctx.MessageID, 22 | TimeStamp: ctx.Time, 23 | Raw: ctx, 24 | } 25 | var collection string 26 | switch msg.Raw.MessageType { 27 | case "private": 28 | collection = "cq_messages." + msg.Raw.MessageType + "." + strconv.FormatInt(msg.Raw.UserID, 10) 29 | case "group": 30 | collection = "cq_messages." + msg.Raw.MessageType + "." + strconv.FormatInt(msg.Raw.GroupID, 10) 31 | default: 32 | collection = "cq_messages." + msg.Raw.MessageType 33 | } 34 | con := context.Background() 35 | 36 | loggingComponent := actions.Logging{} 37 | // Encode raw message to JSON 38 | content, _ := json.Marshal(msg.Raw) 39 | 40 | // Cache and Insert Message 41 | loggingComponent.Cache(con, collection, content) 42 | loggingComponent.Insert(con, collection, content) 43 | } 44 | -------------------------------------------------------------------------------- /internal/logging/gocqhttp/types.go: -------------------------------------------------------------------------------- 1 | package gocqhttp 2 | 3 | import "github.com/Elyart-Network/NyaBot/pkg/gocqhttp/callback" 4 | 5 | type MessageData struct { 6 | Sender Sender `bson:"sender"` 7 | Content string `bson:"content"` 8 | MessageID int32 `bson:"message_id"` 9 | TimeStamp int64 `bson:"timestamp"` 10 | Raw callback.Full `bson:"raw"` 11 | } 12 | 13 | type Sender struct { 14 | UserIdentity string `bson:"user_identity"` 15 | UserCard string `bson:"user_card"` 16 | UserNick string `bson:"user_nick"` 17 | } 18 | -------------------------------------------------------------------------------- /internal/lua/common/httpreq.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/Elyart-Network/NyaBot/utils" 6 | log "github.com/sirupsen/logrus" 7 | lua "github.com/yuin/gopher-lua" 8 | luar "layeh.com/gopher-luar" 9 | ) 10 | 11 | type HttpReqFunc struct{} 12 | 13 | func (h *HttpReqFunc) Get(url string, params string) string { 14 | resp, err := utils.GetRequest(url, params) 15 | if err != nil { 16 | log.Warning("[Lua] Error while sending GET request: ", err) 17 | return "" 18 | } 19 | return string(resp) 20 | } 21 | 22 | func (h *HttpReqFunc) GetJson(url string, params string) map[string]any { 23 | var data map[string]any 24 | resp, err := utils.GetRequest(url, params) 25 | if err != nil { 26 | log.Warning("[Lua] Error while sending GET request: ", err) 27 | return nil 28 | } 29 | err = json.Unmarshal(resp, &data) 30 | if err != nil { 31 | log.Warning("[Lua] Error while parsing JSON: ", err) 32 | return nil 33 | } 34 | return data 35 | } 36 | 37 | func (h *HttpReqFunc) Post(url string, params any) string { 38 | resp, err := utils.PostRequest(url, params) 39 | if err != nil { 40 | log.Warning("[Lua] Error while sending POST request: ", err) 41 | return "" 42 | } 43 | return string(resp) 44 | } 45 | 46 | func (h *HttpReqFunc) PostJson(url string, params any) map[string]any { 47 | var data map[string]any 48 | resp, err := utils.PostRequest(url, params) 49 | if err != nil { 50 | log.Warning("[Lua] Error while sending POST request: ", err) 51 | return nil 52 | } 53 | err = json.Unmarshal(resp, &data) 54 | if err != nil { 55 | log.Warning("[Lua] Error while parsing JSON: ", err) 56 | return nil 57 | } 58 | return data 59 | } 60 | 61 | func HttpReq(L *lua.LState) { 62 | var HttpReqFunc = &HttpReqFunc{} 63 | L.SetGlobal("HttpReq", luar.New(L, HttpReqFunc)) 64 | } 65 | -------------------------------------------------------------------------------- /internal/lua/common/system.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "github.com/Elyart-Network/NyaBot/pkg/fastlib/system" 5 | log "github.com/sirupsen/logrus" 6 | lua "github.com/yuin/gopher-lua" 7 | luar "layeh.com/gopher-luar" 8 | "os" 9 | "time" 10 | ) 11 | 12 | type SystemFunc struct{} 13 | 14 | func (s *SystemFunc) Info() system.Info { 15 | return system.AllInfo() 16 | } 17 | 18 | func (s *SystemFunc) Exit(code int) { 19 | os.Exit(code) 20 | } 21 | 22 | func (s *SystemFunc) Sleep(ms int) { 23 | time.Sleep(time.Duration(ms) * time.Millisecond) 24 | } 25 | 26 | func (s *SystemFunc) GetEnv(key string) string { 27 | return os.Getenv(key) 28 | } 29 | 30 | func (s *SystemFunc) SetEnv(key, value string) { 31 | err := os.Setenv(key, value) 32 | if err != nil { 33 | log.Warning("[Lua] SetEnv error: ", err) 34 | } 35 | } 36 | 37 | func (s *SystemFunc) UnsetEnv(key string) { 38 | err := os.Unsetenv(key) 39 | if err != nil { 40 | log.Warning("[Lua] UnsetEnv error: ", err) 41 | } 42 | } 43 | 44 | func System(L *lua.LState) { 45 | var SystemFunc = &SystemFunc{} 46 | L.SetGlobal("Sys", luar.New(L, SystemFunc)) 47 | } 48 | -------------------------------------------------------------------------------- /internal/lua/database/plugin.go: -------------------------------------------------------------------------------- 1 | package database 2 | 3 | import ( 4 | "github.com/Elyart-Network/NyaBot/pkg/database" 5 | lua "github.com/yuin/gopher-lua" 6 | luar "layeh.com/gopher-luar" 7 | ) 8 | 9 | type DBPluginFunc struct{} 10 | 11 | func (p *DBPluginFunc) SetConfig(PName string, CKey string, CValue any) { 12 | database.SetConfig(PName, "Lua", CKey, CValue) 13 | } 14 | 15 | func (p *DBPluginFunc) GetConfig(PName string) map[string]any { 16 | return database.GetConfig(PName, "Lua") 17 | } 18 | 19 | func (p *DBPluginFunc) DelConfig(PName string, CKey string) { 20 | database.DelConfig(PName, "Lua", CKey) 21 | } 22 | 23 | func (p *DBPluginFunc) DelPlugin(PName string) { 24 | database.DelPlugin(PName, "Lua") 25 | } 26 | 27 | func DBPlugin(L *lua.LState) { 28 | var DBPluginFunc = &DBPluginFunc{} 29 | L.SetGlobal("DBPlug", luar.New(L, DBPluginFunc)) 30 | } 31 | -------------------------------------------------------------------------------- /internal/lua/gocqhttp.go: -------------------------------------------------------------------------------- 1 | package lua 2 | 3 | import ( 4 | "github.com/Elyart-Network/NyaBot/internal/lua/runtime" 5 | "github.com/Elyart-Network/NyaBot/pkg/gocqhttp/callback" 6 | "github.com/Elyart-Network/NyaBot/pkg/plugin" 7 | ) 8 | 9 | // CqPlugin a struct for all functions below. 10 | type CqPlugin struct{} 11 | 12 | // Info set plugin info, `Name` has to be unique! 13 | func (p *CqPlugin) Info() plugin.InfoStruct { 14 | return plugin.InfoStruct{ 15 | Name: "cq_internal_lua", 16 | Version: "", 17 | Author: "", 18 | Description: "", 19 | License: "", 20 | Homepage: "", 21 | Repository: "", 22 | Type: "GoCqHttp", 23 | } 24 | } 25 | 26 | // Message process message event from callback. (required) 27 | func (p *CqPlugin) Message(ctx callback.Full) { 28 | runtime.CqLoader(ctx) 29 | } 30 | 31 | // Request process request event from callback. (required) 32 | func (p *CqPlugin) Request(ctx callback.Full) { 33 | runtime.CqLoader(ctx) 34 | } 35 | 36 | // Notice process notice event from callback. (required) 37 | func (p *CqPlugin) Notice(ctx callback.Full) { 38 | runtime.CqLoader(ctx) 39 | } 40 | 41 | // MetaEvent process meta event from callback. (required) 42 | func (p *CqPlugin) MetaEvent(ctx callback.Full) {} 43 | 44 | // init register plugin and depends to plugin manager (frame). 45 | func init() { 46 | plugin.CqRegister(&CqPlugin{}) 47 | } 48 | -------------------------------------------------------------------------------- /internal/lua/gocqhttp/action.go: -------------------------------------------------------------------------------- 1 | package gocqhttp 2 | 3 | import ( 4 | "github.com/Elyart-Network/NyaBot/pkg/fastlib/fastcq" 5 | log "github.com/sirupsen/logrus" 6 | lua "github.com/yuin/gopher-lua" 7 | luar "layeh.com/gopher-luar" 8 | ) 9 | 10 | type ActionFunc struct{} 11 | 12 | func (c *ActionFunc) SetGroupInfo(GroupID int64, GroupName string, Avatar string, UserId int64, Card string, SpecialTitle string, Type int) { 13 | err := fastcq.SetGroupInfo(GroupID, GroupName, Avatar, UserId, Card, SpecialTitle, Type) 14 | if err != nil { 15 | log.Warning("[Lua] SetGroupInfo error: ", err) 16 | } 17 | } 18 | 19 | func (c *ActionFunc) SetGroupAdmin(GroupID int64, UserId int64, Enable bool) { 20 | err := fastcq.SetGroupAdmin(GroupID, UserId, Enable) 21 | if err != nil { 22 | log.Warning("[Lua] SetGroupAdmin error: ", err) 23 | } 24 | } 25 | 26 | func (c *ActionFunc) GroupBan(GroupID int64, UserID int64, Duration uint32, DeBan bool) { 27 | err := fastcq.GroupBan(GroupID, UserID, Duration, DeBan) 28 | if err != nil { 29 | log.Warning("[Lua] GroupBan error: ", err) 30 | } 31 | } 32 | 33 | func (c *ActionFunc) GroupMute(GroupID int64, UnMute bool) { 34 | err := fastcq.GroupMute(GroupID, UnMute) 35 | if err != nil { 36 | log.Warning("[Lua] GroupMute error: ", err) 37 | } 38 | } 39 | 40 | func (c *ActionFunc) GroupEssenceMsg(MessageID int32, Remove bool) { 41 | err := fastcq.GroupEssenceMsg(MessageID, Remove) 42 | if err != nil { 43 | log.Warning("[Lua] GroupEssenceMsg error: ", err) 44 | } 45 | } 46 | 47 | func (c *ActionFunc) GroupSendNotice(GroupID int64, Content string, Image string) { 48 | err := fastcq.GroupSendNotice(GroupID, Content, Image) 49 | if err != nil { 50 | log.Warning("[Lua] GroupSendNotice error: ", err) 51 | } 52 | } 53 | 54 | func (c *ActionFunc) GroupKick(GroupID int64, UserID int64, RejectAddRequest bool) { 55 | err := fastcq.GroupKick(GroupID, UserID, RejectAddRequest) 56 | if err != nil { 57 | log.Warning("[Lua] GroupKick error: ", err) 58 | } 59 | } 60 | 61 | func (c *ActionFunc) LeaveGroup(GroupID int64) { 62 | err := fastcq.LeaveGroup(GroupID) 63 | if err != nil { 64 | log.Warning("[Lua] LeaveGroup error: ", err) 65 | } 66 | } 67 | 68 | func (c *ActionFunc) DismissGroup(GroupID int64) { 69 | err := fastcq.DismissGroup(GroupID) 70 | if err != nil { 71 | log.Warning("[Lua] DismissGroup error: ", err) 72 | } 73 | } 74 | 75 | func (c *ActionFunc) SendGroupSign(GroupID int64) { 76 | err := fastcq.SendGroupSign(GroupID) 77 | if err != nil { 78 | log.Warning("[Lua] SendGroupSign error: ", err) 79 | } 80 | } 81 | 82 | func (c *ActionFunc) SetEssenceMsg(MessageID int32, Remove bool) { 83 | err := fastcq.SetEssenceMsg(MessageID, Remove) 84 | if err != nil { 85 | log.Warning("[Lua] SetEssenceMsg error: ", err) 86 | } 87 | } 88 | 89 | func Action(L *lua.LState) { 90 | var ActionFunc = &ActionFunc{} 91 | L.SetGlobal("CqAct", luar.New(L, ActionFunc)) 92 | } 93 | -------------------------------------------------------------------------------- /internal/lua/gocqhttp/cqcode.go: -------------------------------------------------------------------------------- 1 | package gocqhttp 2 | 3 | import ( 4 | "github.com/Elyart-Network/NyaBot/pkg/gocqhttp/cqcode" 5 | "github.com/Elyart-Network/NyaBot/pkg/gocqhttp/types" 6 | lua "github.com/yuin/gopher-lua" 7 | luar "layeh.com/gopher-luar" 8 | ) 9 | 10 | type CqCodeFunc struct{} 11 | 12 | func (c CqCodeFunc) Find(msg string) []string { 13 | return cqcode.Find(msg) 14 | } 15 | 16 | func (c CqCodeFunc) Decode(str string) any { 17 | return cqcode.Decode(str) 18 | } 19 | 20 | func (c CqCodeFunc) DecodeOne(code string, key string) string { 21 | return cqcode.Decode(code)[key] 22 | } 23 | 24 | func (c CqCodeFunc) Face(id string) string { 25 | data := types.FaceData{ID: id} 26 | return cqcode.Face(data) 27 | } 28 | 29 | func (c CqCodeFunc) Record(File string, Magic string, Cache string, Proxy string, Timeout string) string { 30 | data := types.RecordData{ 31 | File: File, 32 | Magic: Magic, 33 | Cache: Cache, 34 | Proxy: Proxy, 35 | Timeout: Timeout, 36 | } 37 | return cqcode.Record(data) 38 | } 39 | 40 | func (c CqCodeFunc) Video(File string) string { 41 | data := types.VideoData{ 42 | File: File, 43 | } 44 | return cqcode.Video(data) 45 | } 46 | 47 | func (c CqCodeFunc) VideoFull(File string, Cover string, Thread string) string { 48 | data := types.VideoData{ 49 | File: File, 50 | Cover: Cover, 51 | Thread: Thread, 52 | } 53 | return cqcode.VideoFull(data) 54 | } 55 | 56 | func (c CqCodeFunc) At(QQ string, Name string) string { 57 | data := types.AtData{ 58 | QQ: QQ, 59 | Name: Name, 60 | } 61 | return cqcode.At(data) 62 | } 63 | 64 | func (c CqCodeFunc) Rps() string { 65 | return cqcode.Rps() 66 | } 67 | 68 | func (c CqCodeFunc) Dice() string { 69 | return cqcode.Dice() 70 | } 71 | 72 | func (c CqCodeFunc) Shake() string { 73 | return cqcode.Shake() 74 | } 75 | 76 | func (c CqCodeFunc) Anonymous() string { 77 | return cqcode.Anonymous() 78 | } 79 | 80 | func (c CqCodeFunc) Share(URL string, Title string) string { 81 | data := types.ShareData{ 82 | URL: URL, 83 | Title: Title, 84 | } 85 | return cqcode.Share(data) 86 | } 87 | 88 | func (c CqCodeFunc) ShareFull(URL string, Title string, Content string, Image string) string { 89 | data := types.ShareData{ 90 | URL: URL, 91 | Title: Title, 92 | Content: Content, 93 | Image: Image, 94 | } 95 | return cqcode.ShareFull(data) 96 | } 97 | 98 | func (c CqCodeFunc) Contact(Type string, ID string) string { 99 | data := types.ContactData{ 100 | Type: Type, 101 | ID: ID, 102 | } 103 | return cqcode.Contact(data) 104 | } 105 | 106 | func (c CqCodeFunc) Location(Lat string, Lon string) string { 107 | data := types.LocationData{ 108 | Lat: Lat, 109 | Lon: Lon, 110 | } 111 | return cqcode.Location(data) 112 | } 113 | 114 | func (c CqCodeFunc) LocationFull(Lat string, Lon string, Title string, Content string) string { 115 | data := types.LocationData{ 116 | Lat: Lat, 117 | Lon: Lon, 118 | Title: Title, 119 | Content: Content, 120 | } 121 | return cqcode.LocationFull(data) 122 | } 123 | 124 | func (c CqCodeFunc) Music(Type string, ID string) string { 125 | data := types.MusicData{Type: Type, ID: ID} 126 | return cqcode.Music(data) 127 | } 128 | 129 | func (c CqCodeFunc) MusicFull(Type string, ID string, Audio string, Title string, Content string, Image string) string { 130 | data := types.MusicData{ 131 | Type: Type, 132 | ID: ID, 133 | Audio: Audio, 134 | Title: Title, 135 | Content: Content, 136 | Image: Image, 137 | } 138 | return cqcode.MusicFull(data) 139 | } 140 | 141 | func (c CqCodeFunc) Image(File string, URL string) string { 142 | data := types.ImageData{File: File, Url: URL} 143 | return cqcode.Image(data) 144 | } 145 | 146 | func (c CqCodeFunc) ImageFull(File string, Type string, SubType string, URL string, Cache string, ID string, Thread string) string { 147 | data := types.ImageData{ 148 | File: File, 149 | Type: Type, 150 | SubType: SubType, 151 | Url: URL, 152 | Cache: Cache, 153 | ID: ID, 154 | Thread: Thread, 155 | } 156 | return cqcode.ImageFull(data) 157 | } 158 | 159 | func (c CqCodeFunc) Reply(ID string) string { 160 | data := types.ReplyData{ID: ID} 161 | return cqcode.Reply(data) 162 | } 163 | 164 | func (c CqCodeFunc) ReplyFull(ID string, Text string, QQ string, Time string, Seq string) string { 165 | data := types.ReplyData{ 166 | ID: ID, 167 | Text: Text, 168 | QQ: QQ, 169 | Time: Time, 170 | Seq: Seq, 171 | } 172 | return cqcode.ReplyFull(data) 173 | } 174 | 175 | func (c CqCodeFunc) RedBag(Title string) string { 176 | data := types.RedBagData{Title: Title} 177 | return cqcode.RedBag(data) 178 | } 179 | 180 | func (c CqCodeFunc) Poke(QQ string) string { 181 | data := types.PokeData{QQ: QQ} 182 | return cqcode.Poke(data) 183 | } 184 | 185 | func (c CqCodeFunc) Gift(QQ string, ID string) string { 186 | data := types.GiftData{ 187 | QQ: QQ, 188 | ID: ID, 189 | } 190 | return cqcode.Gift(data) 191 | } 192 | 193 | func (c CqCodeFunc) Forward(ID string) string { 194 | data := types.ForwardData{ID: ID} 195 | return cqcode.Forward(data) 196 | } 197 | 198 | func (c CqCodeFunc) Xml(Data string, ResID string) string { 199 | data := types.XmlData{ 200 | Data: Data, 201 | ResID: ResID, 202 | } 203 | return cqcode.Xml(data) 204 | } 205 | 206 | func (c CqCodeFunc) Json(Data string) string { 207 | data := types.JsonData{Data: Data} 208 | return cqcode.Json(data) 209 | } 210 | 211 | func (c CqCodeFunc) JsonRich(Data string, ResID string) string { 212 | data := types.JsonData{ 213 | Data: Data, 214 | ResID: ResID, 215 | } 216 | return cqcode.JsonRich(data) 217 | } 218 | 219 | func (c CqCodeFunc) CardImage(File string) string { 220 | data := types.CardImageData{File: File} 221 | return cqcode.CardImage(data) 222 | } 223 | 224 | func (c CqCodeFunc) CardImageFull(File string, MinWidth string, MaxWidth string, MinHeight string, MaxHeight string, Source string, Icon string) string { 225 | data := types.CardImageData{ 226 | File: File, 227 | MinWidth: MinWidth, 228 | MaxWidth: MaxWidth, 229 | MinHeight: MinHeight, 230 | MaxHeight: MaxHeight, 231 | Source: Source, 232 | Icon: Icon, 233 | } 234 | return cqcode.CardImageFull(data) 235 | } 236 | 237 | func (c CqCodeFunc) Tts(Text string) string { 238 | data := types.TtsData{Text: Text} 239 | return cqcode.Tts(data) 240 | } 241 | 242 | func (c CqCodeFunc) CqCode(L *lua.LState) { 243 | var CqCodeFunc = &CqCodeFunc{} 244 | L.SetGlobal("CqCode", luar.New(L, CqCodeFunc)) 245 | } 246 | -------------------------------------------------------------------------------- /internal/lua/gocqhttp/getdata.go: -------------------------------------------------------------------------------- 1 | package gocqhttp 2 | 3 | import ( 4 | "github.com/Elyart-Network/NyaBot/pkg/fastlib/fastcq" 5 | "github.com/Elyart-Network/NyaBot/pkg/gocqhttp/types" 6 | log "github.com/sirupsen/logrus" 7 | lua "github.com/yuin/gopher-lua" 8 | luar "layeh.com/gopher-luar" 9 | ) 10 | 11 | type GetDataFunc struct{} 12 | 13 | func (c *GetDataFunc) GetGroupMembers(GroupID int64) []types.GroupMemberInfoObject { 14 | members, err := fastcq.GetGroupMembers(GroupID) 15 | if err != nil { 16 | log.Warning("[Lua] GetGroupMembers error: ", err) 17 | } 18 | return members.Data 19 | } 20 | 21 | func GetData(L *lua.LState) { 22 | var GetDataFunc = &GetDataFunc{} 23 | L.SetGlobal("CqGet", luar.New(L, GetDataFunc)) 24 | } 25 | -------------------------------------------------------------------------------- /internal/lua/gocqhttp/message.go: -------------------------------------------------------------------------------- 1 | package gocqhttp 2 | 3 | import ( 4 | "github.com/Elyart-Network/NyaBot/pkg/fastlib/fastcq" 5 | "github.com/Elyart-Network/NyaBot/pkg/gocqhttp/cqcode" 6 | "github.com/Elyart-Network/NyaBot/pkg/gocqhttp/types" 7 | log "github.com/sirupsen/logrus" 8 | lua "github.com/yuin/gopher-lua" 9 | luar "layeh.com/gopher-luar" 10 | "strconv" 11 | ) 12 | 13 | type MessageFunc struct{} 14 | 15 | func (c *MessageFunc) SendMsg(Message string, Id int64, IsGroup bool) { 16 | _, err := fastcq.SendMsg(Message, Id, IsGroup) 17 | if err != nil { 18 | log.Warning("[Lua] SendMsg error: ", err) 19 | } 20 | } 21 | 22 | func (c *MessageFunc) Reply(Message string, Id int64, IsGroup bool, To int) { 23 | ReplyCodeData := types.ReplyData{ID: strconv.Itoa(To)} 24 | ReplyCode := cqcode.Reply(ReplyCodeData) 25 | _, err := fastcq.SendMsg(ReplyCode+Message, Id, IsGroup) 26 | if err != nil { 27 | log.Warning("[Lua] Reply error: ", err) 28 | } 29 | } 30 | 31 | func (c *MessageFunc) SendPic(Url string, Type string, Id int64, IsGroup bool) { 32 | PicData := types.ImageData{ 33 | File: "pic." + Type, 34 | Url: Url, 35 | } 36 | _, err := fastcq.SendMsg(cqcode.Image(PicData), Id, IsGroup) 37 | if err != nil { 38 | log.Warning("[Lua] SendPic error: ", err) 39 | } 40 | } 41 | 42 | var ForwardMessages []any 43 | 44 | func (c *MessageFunc) SetIdForward(MessageID string) { 45 | data := fastcq.GenIdForward(MessageID) 46 | ForwardMessages = append(ForwardMessages, data) 47 | } 48 | 49 | func (c *MessageFunc) SetCustomForward(Name string, Id string, Content string) { 50 | data := fastcq.GenCustomForward(Name, Id, Content) 51 | ForwardMessages = append(ForwardMessages, data) 52 | } 53 | 54 | func (c *MessageFunc) SendForwardMsg(Id int64, IsGroup bool) { 55 | _, err := fastcq.SendForwardMsg(ForwardMessages, Id, IsGroup) 56 | if err != nil { 57 | log.Warning("[Lua] SendForwardMsg error: ", err) 58 | } 59 | ForwardMessages = nil 60 | } 61 | 62 | func (c *MessageFunc) DeleteMsg(MessageID int32) { 63 | err := fastcq.DeleteMsg(MessageID) 64 | if err != nil { 65 | log.Warning("[Lua] DeleteMsg error: ", err) 66 | } 67 | } 68 | 69 | func Message(L *lua.LState) { 70 | var MessageFunc = &MessageFunc{} 71 | L.SetGlobal("CqMsg", luar.New(L, MessageFunc)) 72 | } 73 | -------------------------------------------------------------------------------- /internal/lua/gocqhttp/request.go: -------------------------------------------------------------------------------- 1 | package gocqhttp 2 | 3 | import ( 4 | "github.com/Elyart-Network/NyaBot/pkg/fastlib/fastcq" 5 | log "github.com/sirupsen/logrus" 6 | lua "github.com/yuin/gopher-lua" 7 | luar "layeh.com/gopher-luar" 8 | ) 9 | 10 | type RequestFunc struct{} 11 | 12 | func (c *RequestFunc) FriendReq(Flag string, Approve bool, Remark string) { 13 | err := fastcq.FriendReq(Flag, Approve, Remark) 14 | if err != nil { 15 | log.Warning("[Lua] FriendReq error: ", err) 16 | } 17 | } 18 | 19 | func (c *RequestFunc) GroupReq(Flag string, Type string, Approve bool, Reason string) { 20 | err := fastcq.GroupReq(Flag, Type, Approve, Reason) 21 | if err != nil { 22 | log.Warning("[Lua] GroupReq error: ", err) 23 | } 24 | } 25 | 26 | func Request(L *lua.LState) { 27 | var RequestFunc = &RequestFunc{} 28 | L.SetGlobal("CqReq", luar.New(L, RequestFunc)) 29 | } 30 | -------------------------------------------------------------------------------- /internal/lua/runtime/loader.go: -------------------------------------------------------------------------------- 1 | package runtime 2 | 3 | import ( 4 | "github.com/Elyart-Network/NyaBot/config" 5 | "github.com/Elyart-Network/NyaBot/pkg/gocqhttp/callback" 6 | "github.com/Elyart-Network/NyaBot/pkg/webhook" 7 | log "github.com/sirupsen/logrus" 8 | "strings" 9 | ) 10 | 11 | type CallbackData struct { 12 | WhCall webhook.Data 13 | CqCall callback.Full 14 | } 15 | 16 | var luaDir = config.Get("plugin.lua_script_dir").(string) 17 | 18 | func LoadScript(data CallbackData) { 19 | GetScripts() 20 | go func() { 21 | for _, script := range scripts { 22 | if strings.HasSuffix(script.FileName, ".lua") && script.Enable { 23 | LVM(luaDir+"/"+script.FileName, data) 24 | log.Debug("[LuaVM] Executed lua script. @Name:", script.Name) 25 | } else if script.Name == "DEFAULT" { 26 | continue 27 | } 28 | } 29 | }() 30 | } 31 | 32 | func WhLoader(ctx webhook.Data) { 33 | var data = CallbackData{ 34 | WhCall: ctx, 35 | } 36 | LoadScript(data) 37 | } 38 | 39 | func CqLoader(ctx callback.Full) { 40 | var data = CallbackData{ 41 | CqCall: ctx, 42 | } 43 | LoadScript(data) 44 | } 45 | -------------------------------------------------------------------------------- /internal/lua/runtime/luavm.go: -------------------------------------------------------------------------------- 1 | package runtime 2 | 3 | import ( 4 | "github.com/Elyart-Network/NyaBot/internal/lua/common" 5 | "github.com/Elyart-Network/NyaBot/internal/lua/database" 6 | "github.com/Elyart-Network/NyaBot/internal/lua/gocqhttp" 7 | log "github.com/sirupsen/logrus" 8 | lua "github.com/yuin/gopher-lua" 9 | luar "layeh.com/gopher-luar" 10 | ) 11 | 12 | func LVM(path string, data CallbackData) { 13 | L := lua.NewState() 14 | defer L.Close() 15 | // send callback data to the lua script 16 | L.SetGlobal("Callback", luar.New(L, data)) 17 | // register modules to the table 18 | common.HttpReq(L) 19 | common.System(L) 20 | gocqhttp.Message(L) 21 | gocqhttp.Request(L) 22 | gocqhttp.Action(L) 23 | gocqhttp.GetData(L) 24 | database.DBPlugin(L) 25 | // load and run the script 26 | if err := L.DoFile(path); err != nil { 27 | log.Error("[Lua] Error running lua script: ", err) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /internal/lua/runtime/scripts.go: -------------------------------------------------------------------------------- 1 | package runtime 2 | 3 | import ( 4 | "github.com/Elyart-Network/NyaBot/config" 5 | log "github.com/sirupsen/logrus" 6 | "gopkg.in/ini.v1" 7 | "os" 8 | ) 9 | 10 | func init() { 11 | _, err := os.Stat(luaDir) 12 | if os.IsNotExist(err) { 13 | log.Infoln("[Lua] Scripts folder not found, creating one...") 14 | err := os.Mkdir(luaDir, os.ModePerm) 15 | if err != nil { 16 | log.Error("[Lua] Error creating scripts folder: ", err) 17 | return 18 | } 19 | } else if err != nil { 20 | log.Error("[Lua] Error checking scripts folder: ", err) 21 | return 22 | } 23 | _, err = os.Stat(luaDir + "/lua.ini") 24 | if os.IsNotExist(err) { 25 | file, err := os.Create(luaDir + "/lua.ini") 26 | defer func(file *os.File) { 27 | err := file.Close() 28 | if err != nil { 29 | log.Error("[Lua] Error closing lua.ini: ", err) 30 | return 31 | } 32 | }(file) 33 | var defaultCnf = []byte("[example]\nenable = false\nscript = example.lua\n") 34 | _, err = file.Write(defaultCnf) 35 | if err != nil { 36 | log.Error("[Lua] Error writing lua.ini: ", err) 37 | return 38 | } 39 | } else if err != nil { 40 | log.Error("[Lua] Error checking lua.ini: ", err) 41 | return 42 | } 43 | } 44 | 45 | type luaScript struct { 46 | Name string 47 | Enable bool 48 | FileName string 49 | } 50 | 51 | var scripts []luaScript 52 | 53 | func GetScripts() { 54 | enable := config.Get("plugin.lua_enable").(bool) 55 | if !enable { 56 | return 57 | } 58 | clearScripts() 59 | cfg, err := ini.Load(luaDir + "/lua.ini") 60 | if err != nil { 61 | log.Error("[Lua] Error loading lua.ini: ", err) 62 | return 63 | } 64 | for _, section := range cfg.Sections() { 65 | scripts = append(scripts, luaScript{ 66 | Name: section.Name(), 67 | Enable: section.Key("enable").MustBool(false), 68 | FileName: section.Key("script").String(), 69 | }) 70 | } 71 | } 72 | 73 | func clearScripts() { 74 | scripts = nil 75 | } 76 | -------------------------------------------------------------------------------- /internal/lua/webhook.go: -------------------------------------------------------------------------------- 1 | package lua 2 | 3 | import ( 4 | "github.com/Elyart-Network/NyaBot/internal/lua/runtime" 5 | "github.com/Elyart-Network/NyaBot/pkg/plugin" 6 | "github.com/Elyart-Network/NyaBot/pkg/webhook" 7 | ) 8 | 9 | // WhPlugin a struct for all functions below. 10 | type WhPlugin struct{} 11 | 12 | // Info set plugin info, `Name` has to be unique! 13 | func (p *WhPlugin) Info() plugin.InfoStruct { 14 | return plugin.InfoStruct{ 15 | Name: "wh_internal_lua", 16 | Version: "", 17 | Author: "", 18 | Description: "", 19 | License: "", 20 | Homepage: "", 21 | Repository: "", 22 | Type: "Webhook", 23 | } 24 | } 25 | 26 | // Receive process webhook data from callback. (required) 27 | func (p *WhPlugin) Receive(callback webhook.Data) { 28 | runtime.WhLoader(callback) 29 | } 30 | 31 | // init register plugin and depends to plugin manager (frame). 32 | func init() { 33 | plugin.WhRegister(&WhPlugin{}) 34 | } 35 | -------------------------------------------------------------------------------- /internal/mirai/bot.go: -------------------------------------------------------------------------------- 1 | package mirai 2 | -------------------------------------------------------------------------------- /logger/logrus.go: -------------------------------------------------------------------------------- 1 | package logger 2 | 3 | import ( 4 | "github.com/Elyart-Network/NyaBot/config" 5 | "github.com/gin-gonic/gin" 6 | log "github.com/sirupsen/logrus" 7 | "os" 8 | "time" 9 | ) 10 | 11 | func init() { 12 | FileLogger := config.Get("server.file_logger").(bool) 13 | DebugMode := config.Get("server.debug_mode").(bool) 14 | 15 | if FileLogger { 16 | gin.DisableConsoleColor() 17 | file, err := os.OpenFile("app.log", os.O_APPEND|os.O_CREATE|os.O_RDWR, 0666) 18 | if err != nil { 19 | log.Panicln("Error opening log file: ", err) 20 | } 21 | log.SetFormatter(&log.JSONFormatter{}) 22 | log.SetOutput(file) 23 | log.SetLevel(log.DebugLevel) 24 | } else { 25 | log.SetFormatter(&log.JSONFormatter{}) 26 | log.SetOutput(os.Stdout) 27 | log.SetLevel(log.WarnLevel) 28 | } 29 | 30 | if DebugMode { 31 | gin.SetMode(gin.DebugMode) 32 | log.SetLevel(log.DebugLevel) 33 | } else { 34 | gin.SetMode(gin.ReleaseMode) 35 | } 36 | } 37 | 38 | func Gin() gin.HandlerFunc { 39 | return func(ctx *gin.Context) { 40 | startTime := time.Now() 41 | ctx.Next() 42 | endTime := time.Now() 43 | latencyTime := endTime.Sub(startTime) 44 | reqMethod := ctx.Request.Method 45 | reqUri := ctx.Request.RequestURI 46 | statusCode := ctx.Writer.Status() 47 | clientIP := ctx.ClientIP() 48 | 49 | log.WithFields(log.Fields{ 50 | "METHOD": reqMethod, 51 | "URI": reqUri, 52 | "STATUS": statusCode, 53 | "LATENCY": latencyTime, 54 | "CLIENT_IP": clientIP, 55 | }).Info("HTTP REQUEST") 56 | 57 | ctx.Next() 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /pkg/database/plugin.go: -------------------------------------------------------------------------------- 1 | package database 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/Elyart-Network/NyaBot/data/actions" 6 | "github.com/Elyart-Network/NyaBot/data/models" 7 | log "github.com/sirupsen/logrus" 8 | ) 9 | 10 | func SetConfig(PName string, PType string, CKey string, CValue any) { 11 | // Prepare config map 12 | cfg := make(map[string]any) 13 | pluginComponent := actions.Plugin{} 14 | orig, err := pluginComponent.GetConfig(PName, PType) 15 | if err != nil { 16 | log.Debug("[DBPlugin] Get config event caught err: ", err) 17 | } 18 | 19 | // Save orig data to a map when key exists. 20 | if err == nil { 21 | log.Debug("[DBPlugin] Getting a existed plugin's config.") 22 | err := json.Unmarshal([]byte(orig.Config), &cfg) 23 | if err != nil { 24 | log.Error("[DBPlugin] Failed to Unmarshal JSON: ", err) 25 | return 26 | } 27 | } 28 | 29 | // Save CKey with CValue 30 | cfg[CKey] = CValue 31 | err = pluginComponent.SaveConfig(orig.ID, PName, PType, cfg, "") 32 | if err != nil { 33 | log.Error("[DBPlugin] Error saving config to DB: ", err) 34 | return 35 | } 36 | } 37 | 38 | func GetConfig(PName string, PType string) map[string]any { 39 | // Prepare config map 40 | cfg := make(map[string]any) 41 | pluginComponent := actions.Plugin{} 42 | orig, err := pluginComponent.GetConfig(PName, PType) 43 | if err != nil { 44 | log.Error("[DBPlugin] Error getting config from DB: ", err) 45 | return nil 46 | } 47 | 48 | // Return when plugin is not exist 49 | if (orig == models.Plugin{ 50 | Name: PName, 51 | Type: PType, 52 | }) { 53 | log.Debug("[DBPlugin] Getting a not existed plugin's config.") 54 | return nil 55 | } 56 | 57 | // Unmarshal config JSON 58 | err = json.Unmarshal([]byte(orig.Config), &cfg) 59 | if err != nil { 60 | log.Error("[DBPlugin] Failed to Marshal JSON: ", err) 61 | return nil 62 | } 63 | return cfg 64 | } 65 | 66 | func DelConfig(PName string, PType string, CKey string) { 67 | // Prepare config map 68 | cfg := make(map[string]any) 69 | pluginComponent := actions.Plugin{} 70 | orig, err := pluginComponent.GetConfig(PName, PType) 71 | if err != nil { 72 | log.Error("[DBPlugin] Error getting config from DB: ", err) 73 | return 74 | } 75 | 76 | // Return when plugin is not exist 77 | if (orig == models.Plugin{ 78 | Name: PName, 79 | Type: PType, 80 | }) { 81 | log.Debug("[DBPlugin] Getting a not existed plugin's config.") 82 | return 83 | } 84 | 85 | // Unmarshal config JSON 86 | err = json.Unmarshal([]byte(orig.Config), &cfg) 87 | if err != nil { 88 | log.Error("[DBPlugin] Failed to Marshal JSON: ", err) 89 | return 90 | } 91 | 92 | // Remove CKey from map 93 | delete(cfg, CKey) 94 | if len(cfg) == 0 { 95 | DelPlugin(PName, PType) 96 | return 97 | } 98 | 99 | // Update config 100 | data, err := json.Marshal(cfg) 101 | if err != nil { 102 | log.Error("[DBPlugin] Failed to Marshal JSON: ", err) 103 | return 104 | } 105 | err = pluginComponent.SaveConfig(orig.ID, PName, PType, data, "") 106 | if err != nil { 107 | log.Error("[DBPlugin] Error saving config to DB: ", err) 108 | return 109 | } 110 | } 111 | 112 | func DelPlugin(PName string, PType string) { 113 | // Delete plugin from table 114 | pluginComponent := actions.Plugin{} 115 | err := pluginComponent.DeleteConfig(PName, PType) 116 | if err != nil { 117 | log.Error("[DBPlugin] Error deleting plugin from DB: ", err) 118 | return 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /pkg/fastlib/fastcq/gocqhttp.go: -------------------------------------------------------------------------------- 1 | package fastcq 2 | 3 | import ( 4 | "errors" 5 | "github.com/Elyart-Network/NyaBot/pkg/gocqhttp/common" 6 | "github.com/Elyart-Network/NyaBot/pkg/gocqhttp/friend" 7 | "github.com/Elyart-Network/NyaBot/pkg/gocqhttp/group" 8 | "github.com/Elyart-Network/NyaBot/pkg/gocqhttp/system" 9 | "github.com/Elyart-Network/NyaBot/pkg/gocqhttp/types" 10 | "log" 11 | ) 12 | 13 | // SendMsg send message to group or user. 14 | // Message: Message to send. 15 | // ID: Group ID or User ID. 16 | // IsGroup: true for group, false for user. 17 | func SendMsg(Message string, Id int64, IsGroup bool) (int32, error) { 18 | switch IsGroup { 19 | case true: 20 | data := types.SendGroupMsgData{ 21 | GroupID: Id, 22 | Message: Message, 23 | AutoEscape: false, 24 | } 25 | msg, err := common.SendGroupMsg(data) 26 | if err != nil { 27 | return 0, err 28 | } 29 | return msg.Data.MessageID, nil 30 | case false: 31 | data := types.SendPrivateMsgData{ 32 | UserID: Id, 33 | Message: Message, 34 | AutoEscape: false, 35 | } 36 | msg, err := common.SendPrivateMsg(data) 37 | if err != nil { 38 | return 0, err 39 | } 40 | return msg.Data.MessageID, nil 41 | } 42 | return 0, errors.New("unknown error") 43 | } 44 | 45 | // GetMsg get message from message ID. 46 | func GetMsg(MessageID int32) (types.GetMsgResp, error) { 47 | data := types.GetMsgData{ 48 | MessageID: MessageID, 49 | } 50 | msg, err := common.GetMsg(data) 51 | if err != nil { 52 | return types.GetMsgResp{}, err 53 | } 54 | return msg, nil 55 | } 56 | 57 | // GetForwardMsg get forward message from message ID. 58 | func GetForwardMsg(MessageID string) (types.GetForwardMsgResp, error) { 59 | data := types.GetForwardMsgData{ 60 | MessageID: MessageID, 61 | } 62 | msg, err := common.GetForwardMsg(data) 63 | if err != nil { 64 | log.Println("[FastLib] CqGetForwardMsg Error: ", err) 65 | return types.GetForwardMsgResp{}, err 66 | } 67 | return msg, nil 68 | } 69 | 70 | // GenIdForward generate forward node from message ID. 71 | func GenIdForward(MessageID string) types.ForwardIdNode { 72 | var data = types.ForwardIdData{ 73 | Id: MessageID, 74 | } 75 | var forward = types.ForwardIdNode{ 76 | Type: "node", 77 | Data: data, 78 | } 79 | return forward 80 | } 81 | 82 | // GenCustomForward generate forward node from custom data. 83 | // Name: Name of the sender. 84 | // ID: QQ ID of the sender. 85 | // Content: Content of the message. 86 | func GenCustomForward(Name string, Id string, Content string) types.ForwardCustomNode { 87 | var data = types.ForwardCustomData{ 88 | Name: Name, 89 | Uin: Id, 90 | Content: Content, 91 | } 92 | var forward = types.ForwardCustomNode{ 93 | Type: "node", 94 | Data: data, 95 | } 96 | return forward 97 | } 98 | 99 | // SendForwardMsg send forward message to group or user. 100 | // Message: Message to send. 101 | // ID: Group ID or User ID. 102 | // IsGroup: true for group, false for user. 103 | func SendForwardMsg(Messages any, Id int64, IsGroup bool) (int64, error) { 104 | switch IsGroup { 105 | case true: 106 | data := types.SendGroupForwardMsgData{ 107 | GroupID: Id, 108 | Messages: Messages, 109 | } 110 | msg, err := common.SendGroupForwardMsg(data) 111 | if err != nil { 112 | return 0, err 113 | } 114 | return msg.Data.MessageID, nil 115 | case false: 116 | data := types.SendPrivateForwardMsgData{ 117 | UserID: Id, 118 | Messages: Messages, 119 | } 120 | msg, err := common.SendPrivateForwardMsg(data) 121 | if err != nil { 122 | return 0, err 123 | } 124 | return msg.Data.MessageID, nil 125 | } 126 | return 0, errors.New("unknown error") 127 | } 128 | 129 | // DeleteMsg delete message from message ID. 130 | func DeleteMsg(MessageID int32) error { 131 | data := types.DeleteMsgData{ 132 | MessageID: MessageID, 133 | } 134 | _, err := common.DeleteMsg(data) 135 | if err != nil { 136 | return err 137 | } 138 | return nil 139 | } 140 | 141 | // GetImage get image from cached file name. 142 | func GetImage(FileName string) (types.GetImageResp, error) { 143 | data := types.GetImageData{ 144 | File: FileName, 145 | } 146 | msg, err := common.GetImage(data) 147 | if err != nil { 148 | return types.GetImageResp{}, err 149 | } 150 | return msg, nil 151 | } 152 | 153 | // GetRecord get record cached from file name. 154 | func GetRecord(FileName string) (types.GetRecordResp, error) { 155 | data := types.GetRecordData{ 156 | File: FileName, 157 | } 158 | msg, err := common.GetRecord(data) 159 | if err != nil { 160 | return types.GetRecordResp{}, err 161 | } 162 | return msg, nil 163 | } 164 | 165 | // FriendReq process friend request. 166 | // Flag: Request flag, get from request event. 167 | // Approve: true for approve, false for reject. 168 | // Remark: Remark for friend. 169 | func FriendReq(Flag string, Approve bool, Remark string) error { 170 | data := types.SetFriendAddRequestData{ 171 | Flag: Flag, 172 | Approve: Approve, 173 | Remark: Remark, 174 | } 175 | _, err := system.SetFriendAddRequest(data) 176 | if err != nil { 177 | return err 178 | } 179 | return nil 180 | } 181 | 182 | // GroupReq process group request. 183 | // Flag: Request flag, get from request event. 184 | // Type: Request type, get from request event. 185 | // Approve: true for approve, false for reject. 186 | // RejectReason: Reject reason. 187 | func GroupReq(Flag string, Type string, Approve bool, RejectReason string) error { 188 | data := types.SetGroupAddRequestData{ 189 | Flag: Flag, 190 | SubType: Type, 191 | Approve: Approve, 192 | Reason: RejectReason, 193 | } 194 | _, err := system.SetGroupAddRequest(data) 195 | if err != nil { 196 | return err 197 | } 198 | return nil 199 | } 200 | 201 | // GetStrangerInfo get stranger info. 202 | func GetStrangerInfo(UserID int64) (types.GetStrangerInfoResp, error) { 203 | data := types.GetStrangerInfoData{ 204 | UserID: UserID, 205 | NoCache: false, 206 | } 207 | msg, err := friend.GetStrangerInfo(data) 208 | if err != nil { 209 | return types.GetStrangerInfoResp{}, err 210 | } 211 | return msg, nil 212 | } 213 | 214 | // GetGroupMemberInfo get group member info. 215 | func GetGroupMemberInfo(GroupID int64, UserID int64) (types.GetGroupMemberInfoResp, error) { 216 | data := types.GetGroupMemberInfoData{ 217 | GroupID: GroupID, 218 | UserID: UserID, 219 | NoCache: false, 220 | } 221 | msg, err := group.GetGroupMemberInfo(data) 222 | if err != nil { 223 | return types.GetGroupMemberInfoResp{}, err 224 | } 225 | return msg, nil 226 | } 227 | 228 | // GetGroupMembers get group member list. 229 | func GetGroupMembers(GroupID int64) (types.GetGroupMemberListResp, error) { 230 | data := types.GetGroupMemberListData{ 231 | GroupID: GroupID, 232 | NoCache: false, 233 | } 234 | msg, err := group.GetGroupMemberList(data) 235 | if err != nil { 236 | return types.GetGroupMemberListResp{}, err 237 | } 238 | return msg, nil 239 | } 240 | 241 | // GetFriends get friend list. 242 | func GetFriends() (types.GetFriendListResp, error) { 243 | msg, err := friend.GetFriendList() 244 | if err != nil { 245 | return types.GetFriendListResp{}, err 246 | } 247 | return msg, nil 248 | } 249 | 250 | // GetGroups get group list. 251 | func GetGroups() (types.GetGroupListResp, error) { 252 | data := types.GetGroupListData{ 253 | NoCache: false, 254 | } 255 | msg, err := group.GetGroupList(data) 256 | if err != nil { 257 | return types.GetGroupListResp{}, err 258 | } 259 | return msg, nil 260 | } 261 | 262 | // GetGroupInfo get group info. 263 | func GetGroupInfo(GroupID int64) (types.GetGroupInfoResp, error) { 264 | data := types.GetGroupInfoData{ 265 | GroupID: GroupID, 266 | NoCache: false, 267 | } 268 | msg, err := group.GetGroupInfo(data) 269 | if err != nil { 270 | return types.GetGroupInfoResp{}, err 271 | } 272 | return msg, nil 273 | } 274 | 275 | // SetGroupInfo set group info. 276 | // Type 1: GroupID, GroupName set group name. 277 | // Type 2: GroupID, Avatar(path) set group avatar. 278 | // Type 3: GroupID, UserId, Card set group card. 279 | // Type 4: GroupID, UserId, SpecialTitle set group member special title. 280 | func SetGroupInfo(GroupID int64, GroupName string, Avatar string, UserId int64, Card string, SpecialTitle string, Type int) error { 281 | switch Type { 282 | case 1: 283 | data := types.SetGroupNameData{ 284 | GroupID: GroupID, 285 | GroupName: GroupName, 286 | } 287 | _, err := group.SetGroupName(data) 288 | if err != nil { 289 | return err 290 | } 291 | return nil 292 | case 2: 293 | data := types.SetGroupPortraitData{ 294 | GroupID: GroupID, 295 | File: Avatar, 296 | Cache: 1, 297 | } 298 | _, err := group.SetGroupPortrait(data) 299 | if err != nil { 300 | return err 301 | } 302 | return nil 303 | case 3: 304 | data := types.SetGroupCardData{ 305 | GroupID: GroupID, 306 | UserID: UserId, 307 | Card: Card, 308 | } 309 | _, err := group.SetGroupCard(data) 310 | if err != nil { 311 | return err 312 | } 313 | return nil 314 | case 4: 315 | data := types.SetGroupSpecialTitleData{ 316 | GroupID: GroupID, 317 | UserID: UserId, 318 | SpecialTitle: SpecialTitle, 319 | } 320 | _, err := group.SetGroupSpecialTitle(data) 321 | if err != nil { 322 | return err 323 | } 324 | return nil 325 | } 326 | return errors.New("type error") 327 | } 328 | 329 | // SetGroupAdmin set group admin. 330 | func SetGroupAdmin(GroupID int64, UserID int64, Enable bool) error { 331 | data := types.SetGroupAdminData{ 332 | GroupID: GroupID, 333 | UserID: UserID, 334 | Enable: Enable, 335 | } 336 | _, err := group.SetGroupAdmin(data) 337 | if err != nil { 338 | return err 339 | } 340 | return nil 341 | } 342 | 343 | // GroupBan ban group member. 344 | // BanAll true: ban all member. 345 | // DeBan true: unban. 346 | // Duration only work when BanAll is false. 347 | func GroupBan(GroupID int64, UserID int64, Duration uint32, DeBan bool) error { 348 | if DeBan { 349 | Duration = 0 350 | } 351 | data := types.SetGroupBanData{ 352 | GroupID: GroupID, 353 | UserID: UserID, 354 | Duration: Duration, 355 | } 356 | _, err := group.SetGroupBan(data) 357 | if err != nil { 358 | return err 359 | } 360 | return nil 361 | } 362 | 363 | // GroupMute mute group. 364 | func GroupMute(GroupID int64, UnMute bool) error { 365 | data := types.SetGroupWholeBanData{ 366 | GroupID: GroupID, 367 | Enable: UnMute, 368 | } 369 | _, err := group.SetGroupWholeBan(data) 370 | if err != nil { 371 | return err 372 | } 373 | return nil 374 | } 375 | 376 | // GroupEssenceMsg set group essence message. 377 | func GroupEssenceMsg(MessageID int32, Remove bool) error { 378 | switch Remove { 379 | case true: 380 | data := types.DeleteEssenceMsgData{ 381 | MessageID: MessageID, 382 | } 383 | _, err := group.DeleteEssenceMsg(data) 384 | if err != nil { 385 | return err 386 | } 387 | return nil 388 | case false: 389 | data := types.SetEssenceMsgData{ 390 | MessageID: MessageID, 391 | } 392 | _, err := group.SetEssenceMsg(data) 393 | if err != nil { 394 | return err 395 | } 396 | return nil 397 | } 398 | return errors.New("remove error") 399 | } 400 | 401 | // GroupSendNotice send group notice. 402 | func GroupSendNotice(GroupID int64, Content string, Image string) error { 403 | data := types.SendGroupNoticeData{ 404 | GroupID: GroupID, 405 | Content: Content, 406 | Image: Image, 407 | } 408 | _, err := group.SendGroupNotice(data) 409 | if err != nil { 410 | return err 411 | } 412 | return nil 413 | } 414 | 415 | // GroupKick kick group member. 416 | func GroupKick(GroupID int64, UserID int64, RejectAddRequest bool) error { 417 | data := types.SetGroupKickData{ 418 | GroupID: GroupID, 419 | UserID: UserID, 420 | Reject: RejectAddRequest, 421 | } 422 | _, err := group.SetGroupKick(data) 423 | if err != nil { 424 | return err 425 | } 426 | return nil 427 | } 428 | 429 | // LeaveGroup leave group. 430 | func LeaveGroup(GroupID int64) error { 431 | data := types.SetGroupLeaveData{ 432 | GroupID: GroupID, 433 | IsDismiss: false, 434 | } 435 | _, err := group.SetGroupLeave(data) 436 | if err != nil { 437 | return err 438 | } 439 | return nil 440 | } 441 | 442 | // DismissGroup dismiss group. 443 | func DismissGroup(GroupID int64) error { 444 | data := types.SetGroupLeaveData{ 445 | GroupID: GroupID, 446 | IsDismiss: true, 447 | } 448 | _, err := group.SetGroupLeave(data) 449 | if err != nil { 450 | return err 451 | } 452 | return nil 453 | } 454 | 455 | // SendGroupSign send group sign. 456 | func SendGroupSign(GroupID int64) error { 457 | data := types.SendGroupSignData{ 458 | GroupID: GroupID, 459 | } 460 | _, err := group.SendGroupSign(data) 461 | if err != nil { 462 | return err 463 | } 464 | return nil 465 | } 466 | 467 | // SetEssenceMsg set group essence message. 468 | func SetEssenceMsg(MessageID int32, Remove bool) error { 469 | switch Remove { 470 | case true: 471 | data := types.DeleteEssenceMsgData{ 472 | MessageID: MessageID, 473 | } 474 | _, err := group.DeleteEssenceMsg(data) 475 | if err != nil { 476 | return err 477 | } 478 | return nil 479 | case false: 480 | data := types.SetEssenceMsgData{ 481 | MessageID: MessageID, 482 | } 483 | _, err := group.SetEssenceMsg(data) 484 | if err != nil { 485 | return err 486 | } 487 | return nil 488 | } 489 | return errors.New("remove error") 490 | } 491 | -------------------------------------------------------------------------------- /pkg/fastlib/fastcq/message.go: -------------------------------------------------------------------------------- 1 | package fastcq 2 | 3 | import ( 4 | "github.com/Elyart-Network/NyaBot/pkg/gocqhttp/callback" 5 | "github.com/Elyart-Network/NyaBot/pkg/gocqhttp/cqcode" 6 | "github.com/Elyart-Network/NyaBot/pkg/gocqhttp/types" 7 | "strconv" 8 | ) 9 | 10 | type MessageFunc struct { 11 | Cmd string 12 | Raw bool 13 | UserId int64 14 | GroupId int64 15 | Msg string 16 | MsgId int32 17 | IsGroup bool 18 | SMsg []any 19 | SFwd []any 20 | Errors []error 21 | } 22 | 23 | type MsgMiddleware func(*MessageFunc) error 24 | 25 | func (c *MessageFunc) Message(callback callback.Full) *MessageFunc { 26 | switch callback.MessageType { 27 | case "group": 28 | c.IsGroup = true 29 | c.UserId = callback.UserID 30 | c.GroupId = callback.GroupID 31 | case "private": 32 | c.IsGroup = false 33 | c.UserId = callback.UserID 34 | } 35 | c.Msg = callback.MessageData 36 | c.MsgId = callback.MessageID 37 | return c 38 | } 39 | 40 | func (c *MessageFunc) Command(cmd string) *MessageFunc { 41 | c.Cmd = cmd 42 | return c 43 | } 44 | 45 | func (c *MessageFunc) Direct() *MessageFunc { 46 | c.Raw = true 47 | return c 48 | } 49 | 50 | func (c *MessageFunc) Send() *MessageFunc { 51 | if (c.Cmd == c.Msg) || c.Raw { 52 | var Id int64 53 | switch c.IsGroup { 54 | case true: 55 | Id = c.GroupId 56 | case false: 57 | Id = c.UserId 58 | } 59 | if len(c.SFwd) > 0 { 60 | _, err := SendForwardMsg(c.SFwd, Id, c.IsGroup) 61 | if err != nil { 62 | c.Errors = append(c.Errors, err) 63 | } 64 | } 65 | if len(c.SMsg) > 1 { 66 | for _, v := range c.SMsg { 67 | _, err := SendMsg(v.(string), Id, c.IsGroup) 68 | if err != nil { 69 | c.Errors = append(c.Errors, err) 70 | } 71 | } 72 | } else if len(c.SMsg) == 1 { 73 | _, err := SendMsg(c.SMsg[0].(string), Id, c.IsGroup) 74 | if err != nil { 75 | c.Errors = append(c.Errors, err) 76 | } 77 | } 78 | } 79 | return c 80 | } 81 | 82 | func (c *MessageFunc) Text(ctx string) *MessageFunc { 83 | c.SMsg = append(c.SMsg, ctx) 84 | return c 85 | } 86 | 87 | func (c *MessageFunc) Reply(ctx string) *MessageFunc { 88 | ReplyCodeData := types.ReplyData{ID: strconv.Itoa(int(c.MsgId))} 89 | ReplyCode := cqcode.Reply(ReplyCodeData) 90 | c.SMsg = append(c.SMsg, ReplyCode+ctx) 91 | return c 92 | } 93 | 94 | func (c *MessageFunc) IDFwd(id string) *MessageFunc { 95 | data := GenIdForward(id) 96 | c.SFwd = append(c.SFwd, data) 97 | return c 98 | } 99 | 100 | func (c *MessageFunc) CustomFwd(name string, id string, content string) *MessageFunc { 101 | data := GenCustomForward(name, id, content) 102 | c.SFwd = append(c.SFwd, data) 103 | return c 104 | } 105 | 106 | func (c *MessageFunc) Pic(url string) *MessageFunc { 107 | data := types.ImageData{ 108 | File: "img.jpg", 109 | Url: url, 110 | } 111 | c.SMsg = append(c.SMsg, cqcode.Image(data)) 112 | return c 113 | } 114 | 115 | func (c *MessageFunc) Delete() *MessageFunc { 116 | if c.Cmd == c.Msg { 117 | err := DeleteMsg(c.MsgId) 118 | if err != nil { 119 | c.Errors = append(c.Errors, err) 120 | } 121 | } 122 | return c 123 | } 124 | -------------------------------------------------------------------------------- /pkg/fastlib/system/info.go: -------------------------------------------------------------------------------- 1 | package system 2 | 3 | import ( 4 | "github.com/shirou/gopsutil/v3/cpu" 5 | "github.com/shirou/gopsutil/v3/disk" 6 | "github.com/shirou/gopsutil/v3/docker" 7 | "github.com/shirou/gopsutil/v3/host" 8 | "github.com/shirou/gopsutil/v3/load" 9 | "github.com/shirou/gopsutil/v3/mem" 10 | "github.com/shirou/gopsutil/v3/net" 11 | ) 12 | 13 | type Info struct { 14 | CPU []cpu.InfoStat 15 | DiskUsage disk.UsageStat 16 | DiskPartitions []disk.PartitionStat 17 | DiskIOCounters map[string]disk.IOCountersStat 18 | Docker []docker.CgroupDockerStat 19 | Host host.InfoStat 20 | HostUsers []host.UserStat 21 | HostTemperature []host.TemperatureStat 22 | LoadAvg load.AvgStat 23 | LoadMisc load.MiscStat 24 | VMemory mem.VirtualMemoryStat 25 | SMemory mem.SwapMemoryStat 26 | NetIOCounters []net.IOCountersStat 27 | NetConnections []net.ConnectionStat 28 | NetInterfaces []net.InterfaceStat 29 | NetProtoCounters []net.ProtoCountersStat 30 | } 31 | 32 | func AllInfo() Info { 33 | cpuStat, _ := CPU() 34 | diskUsage, _ := DiskUsage() 35 | diskPartitions, _ := DiskPartitions() 36 | diskIOCounters, _ := DiskIOCounters() 37 | dockerStats, _ := Docker() 38 | hostStat, _ := Host() 39 | hostUsers, _ := HostUsers() 40 | hostTemperature, _ := HostTemperature() 41 | loadAvg := LoadAvg() 42 | loadMisc := LoadMisc() 43 | vMemory, _ := VMemory() 44 | sMemory, _ := SMemory() 45 | netIOCounters, _ := NetIOCounters() 46 | netConnections, _ := NetConnections() 47 | netInterfaces, _ := NetInterfaces() 48 | netProtoCounters, _ := NetProtoCounters() 49 | return Info{ 50 | CPU: cpuStat, 51 | DiskUsage: diskUsage, 52 | DiskPartitions: diskPartitions, 53 | DiskIOCounters: diskIOCounters, 54 | Docker: dockerStats, 55 | Host: hostStat, 56 | HostUsers: hostUsers, 57 | HostTemperature: hostTemperature, 58 | LoadAvg: loadAvg, 59 | LoadMisc: loadMisc, 60 | VMemory: vMemory, 61 | SMemory: sMemory, 62 | NetIOCounters: netIOCounters, 63 | NetConnections: netConnections, 64 | NetInterfaces: netInterfaces, 65 | NetProtoCounters: netProtoCounters, 66 | } 67 | } 68 | 69 | func CPU() ([]cpu.InfoStat, error) { 70 | cpuInfo, err := cpu.Info() 71 | if err != nil { 72 | return nil, err 73 | } 74 | return cpuInfo, nil 75 | } 76 | 77 | func DiskUsage() (disk.UsageStat, error) { 78 | diskUsage, err := disk.Usage("/") 79 | if err != nil { 80 | return disk.UsageStat{}, err 81 | } 82 | return *diskUsage, nil 83 | } 84 | 85 | func DiskPartitions() ([]disk.PartitionStat, error) { 86 | diskPartitions, err := disk.Partitions(false) 87 | if err != nil { 88 | return nil, err 89 | } 90 | return diskPartitions, nil 91 | } 92 | 93 | func DiskIOCounters() (map[string]disk.IOCountersStat, error) { 94 | diskIOCounters, err := disk.IOCounters() 95 | if err != nil { 96 | return nil, err 97 | } 98 | return diskIOCounters, nil 99 | } 100 | 101 | func Docker() ([]docker.CgroupDockerStat, error) { 102 | dockerStat, err := docker.GetDockerStat() 103 | if err != nil { 104 | return nil, err 105 | } 106 | return dockerStat, nil 107 | } 108 | 109 | func Host() (host.InfoStat, error) { 110 | hostInfo, err := host.Info() 111 | if err != nil { 112 | return host.InfoStat{}, err 113 | } 114 | return *hostInfo, nil 115 | } 116 | 117 | func HostUsers() ([]host.UserStat, error) { 118 | hostUsers, err := host.Users() 119 | if err != nil { 120 | return nil, err 121 | } 122 | return hostUsers, nil 123 | } 124 | 125 | func HostTemperature() ([]host.TemperatureStat, error) { 126 | hostTemperature, err := host.SensorsTemperatures() 127 | if err != nil { 128 | return nil, err 129 | } 130 | return hostTemperature, nil 131 | } 132 | 133 | func LoadAvg() load.AvgStat { 134 | loadAvg, err := load.Avg() 135 | if err != nil { 136 | return load.AvgStat{} 137 | } 138 | return *loadAvg 139 | } 140 | 141 | func LoadMisc() load.MiscStat { 142 | loadMisc, err := load.Misc() 143 | if err != nil { 144 | return load.MiscStat{} 145 | } 146 | return *loadMisc 147 | } 148 | 149 | func VMemory() (mem.VirtualMemoryStat, error) { 150 | vMemory, err := mem.VirtualMemory() 151 | if err != nil { 152 | return mem.VirtualMemoryStat{}, err 153 | } 154 | return *vMemory, nil 155 | } 156 | 157 | func SMemory() (mem.SwapMemoryStat, error) { 158 | swapMemory, err := mem.SwapMemory() 159 | if err != nil { 160 | return mem.SwapMemoryStat{}, err 161 | } 162 | return *swapMemory, nil 163 | } 164 | 165 | func NetIOCounters() ([]net.IOCountersStat, error) { 166 | netIOCounters, err := net.IOCounters(true) 167 | if err != nil { 168 | return nil, err 169 | } 170 | return netIOCounters, nil 171 | } 172 | 173 | func NetConnections() ([]net.ConnectionStat, error) { 174 | netConnections, err := net.Connections("all") 175 | if err != nil { 176 | return nil, err 177 | } 178 | return netConnections, nil 179 | } 180 | 181 | func NetInterfaces() ([]net.InterfaceStat, error) { 182 | netInterfaces, err := net.Interfaces() 183 | if err != nil { 184 | return nil, err 185 | } 186 | return netInterfaces, nil 187 | } 188 | 189 | func NetProtoCounters() ([]net.ProtoCountersStat, error) { 190 | netProtoCounters, err := net.ProtoCounters([]string{"tcp", "udp"}) 191 | if err != nil { 192 | return nil, err 193 | } 194 | return netProtoCounters, nil 195 | } 196 | -------------------------------------------------------------------------------- /pkg/fastlib/system/time.go: -------------------------------------------------------------------------------- 1 | package system 2 | -------------------------------------------------------------------------------- /pkg/gocqhttp/callback/callback.go: -------------------------------------------------------------------------------- 1 | package callback 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/gin-gonic/gin" 6 | ) 7 | 8 | func Encode(ctx any, ws bool) (full Full, err error) { 9 | if ws { 10 | wsContext := ctx.([]byte) 11 | err = json.Unmarshal(wsContext, &full) 12 | } else { 13 | err = ctx.(*gin.Context).BindJSON(&full) 14 | } 15 | return 16 | } 17 | -------------------------------------------------------------------------------- /pkg/gocqhttp/callback/types.go: -------------------------------------------------------------------------------- 1 | package callback 2 | 3 | type Full struct { 4 | Base 5 | Message 6 | Request 7 | Notice 8 | MetaEvent 9 | Unique 10 | } 11 | 12 | type Base struct { 13 | Time int64 `json:"time"` 14 | SelfID int64 `json:"self_id"` 15 | PostType string `json:"post_type"` 16 | } 17 | 18 | type Message struct { 19 | MessageType string `json:"message_type"` 20 | SubType string `json:"sub_type"` 21 | MessageID int32 `json:"message_id"` 22 | UserID int64 `json:"user_id"` 23 | MessageData string `json:"message"` 24 | RawMessage string `json:"raw_message"` 25 | Font int32 `json:"font"` 26 | Sender SenderObject `json:"sender"` 27 | } 28 | 29 | type Request struct { 30 | RequestType string `json:"request_type"` 31 | } 32 | 33 | type Notice struct { 34 | NoticeType string `json:"notice_type"` 35 | } 36 | 37 | type MetaEvent struct { 38 | MetaEventType string `json:"meta_event_type"` 39 | } 40 | 41 | type Unique struct { 42 | GroupID int64 `json:"group_id"` 43 | OperatorID int64 `json:"operator_id"` 44 | TargetID int64 `json:"target_id"` 45 | TempSource int `json:"temp_source"` 46 | Anonymous AnonymousObject `json:"anonymous"` 47 | UploadFile FileObject `json:"file"` 48 | Duration int64 `json:"duration"` 49 | SenderID int64 `json:"sender_id"` 50 | HonorType string `json:"honor_type"` 51 | Title string `json:"title"` 52 | NewCard string `json:"card_new"` 53 | OldCard string `json:"card_old"` 54 | Client []DeviceObject `json:"client"` 55 | Online bool `json:"online"` 56 | Comment string `json:"comment"` 57 | Flag string `json:"flag"` 58 | Status StatusObject `json:"status"` 59 | Interval int64 `json:"interval"` 60 | } 61 | 62 | type SenderObject struct { 63 | UserID int64 `json:"user_id"` 64 | GroupID int64 `json:"group_id"` 65 | Nickname string `json:"nickname"` 66 | Sex string `json:"sex"` 67 | Age int32 `json:"age"` 68 | Card string `json:"card"` 69 | Area string `json:"area"` 70 | Level string `json:"level"` 71 | Role string `json:"role"` 72 | Title string `json:"title"` 73 | } 74 | 75 | type AnonymousObject struct { 76 | ID int64 `json:"id"` 77 | Name string `json:"name"` 78 | Flag string `json:"flag"` 79 | } 80 | 81 | type FileObject struct { 82 | ID string `json:"id"` 83 | Name string `json:"name"` 84 | Size int64 `json:"size"` 85 | URL string `json:"url"` 86 | BusID int64 `json:"busid"` 87 | } 88 | 89 | type DeviceObject struct { 90 | AppID int64 `json:"app_id"` 91 | DeviceName string `json:"device_name"` 92 | DeviceKind string `json:"device_kind"` 93 | } 94 | 95 | type StatusObject struct { 96 | AppInitialized bool `json:"app_initialized"` 97 | AppEnabled bool `json:"app_enabled"` 98 | PluginsGood bool `json:"plugins_good"` 99 | AppGood bool `json:"app_good"` 100 | Online bool `json:"online"` 101 | Stat StatusStatisticsObject `json:"stat"` 102 | } 103 | 104 | type StatusStatisticsObject struct { 105 | PacketReceived uint64 `json:"PacketReceived"` 106 | PacketSent uint64 `json:"PacketSent"` 107 | PacketLost uint64 `json:"PacketLost"` 108 | MessageReceived uint64 `json:"MessageReceived"` 109 | MessageSent uint64 `json:"MessageSent"` 110 | DisconnectTimes uint32 `json:"DisconnectTimes"` 111 | LostTimes uint32 `json:"LostTimes"` 112 | LastMessageTime int64 `json:"LastMessageTime"` 113 | } 114 | -------------------------------------------------------------------------------- /pkg/gocqhttp/common/file.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "github.com/Elyart-Network/NyaBot/pkg/gocqhttp" 5 | "github.com/Elyart-Network/NyaBot/pkg/gocqhttp/types" 6 | ) 7 | 8 | func UploadGroupFile(data types.UploadGroupFileData) (resp types.Response, err error) { 9 | err = gocqhttp.PostRequest("/upload_group_file", data, &resp) 10 | return 11 | } 12 | 13 | func DeleteGroupFile(data types.DeleteGroupFileData) (resp types.Response, err error) { 14 | err = gocqhttp.PostRequest("/delete_group_file", data, &resp) 15 | return 16 | } 17 | 18 | func DeleteGroupFolder(data types.DeleteGroupFolderData) (resp types.Response, err error) { 19 | err = gocqhttp.PostRequest("/delete_group_folder", data, &resp) 20 | return 21 | } 22 | 23 | func GetGroupFileSystemInfo(data types.GetGroupFileSystemInfoData) (resp types.GetGroupFileSystemInfoResp, err error) { 24 | err = gocqhttp.PostRequest("/get_group_file_system_info", data, &resp) 25 | return 26 | } 27 | 28 | func GetGroupRootFiles(data types.GetGroupRootFilesData) (resp types.GetGroupRootFilesResp, err error) { 29 | err = gocqhttp.PostRequest("/get_group_root_files", data, &resp) 30 | return 31 | } 32 | 33 | func GetGroupFilesByFolder(data types.GetGroupFilesByFolderData) (resp types.GetGroupFilesByFolderResp, err error) { 34 | err = gocqhttp.PostRequest("/get_group_files_by_folder", data, &resp) 35 | return 36 | } 37 | 38 | func GetGroupFileUrl(data types.GetGroupFileUrlData) (resp types.GetGroupFileUrlResp, err error) { 39 | err = gocqhttp.PostRequest("/get_group_file_url", data, &resp) 40 | return 41 | } 42 | 43 | func UploadPrivateFile(data types.UploadPrivateFileData) (resp types.Response, err error) { 44 | err = gocqhttp.PostRequest("/upload_private_file", data, &resp) 45 | return 46 | } 47 | -------------------------------------------------------------------------------- /pkg/gocqhttp/common/image.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "github.com/Elyart-Network/NyaBot/pkg/gocqhttp" 5 | "github.com/Elyart-Network/NyaBot/pkg/gocqhttp/types" 6 | ) 7 | 8 | func GetImage(data types.GetImageData) (resp types.GetImageResp, err error) { 9 | err = gocqhttp.PostRequest("/get_image", data, &resp) 10 | return 11 | } 12 | 13 | func CanSendImage() (resp types.CanSendImageResp, err error) { 14 | err = gocqhttp.GetRequest("/can_send_image", &resp) 15 | return 16 | } 17 | 18 | func OcrImage(data types.OcrImageData) (resp types.OcrImageResp, err error) { 19 | err = gocqhttp.PostRequest("/ocr_image", data, &resp) 20 | return 21 | } 22 | -------------------------------------------------------------------------------- /pkg/gocqhttp/common/message.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "github.com/Elyart-Network/NyaBot/pkg/gocqhttp" 5 | "github.com/Elyart-Network/NyaBot/pkg/gocqhttp/types" 6 | ) 7 | 8 | func DeleteMsg(data types.DeleteMsgData) (resp types.Response, err error) { 9 | err = gocqhttp.PostRequest("/delete_msg", data, &resp) 10 | return 11 | } 12 | 13 | func GetForwardMsg(data types.GetForwardMsgData) (resp types.GetForwardMsgResp, err error) { 14 | err = gocqhttp.PostRequest("/get_forward_msg", data, &resp) 15 | return 16 | } 17 | 18 | func GetGroupMsgHistory(data types.GetGroupMsgHistoryData) (resp types.GetGroupMsgHistoryResp, err error) { 19 | err = gocqhttp.PostRequest("/get_group_msg_history", data, &resp) 20 | return 21 | } 22 | 23 | func GetMsg(data types.GetMsgData) (resp types.GetMsgResp, err error) { 24 | err = gocqhttp.PostRequest("/get_msg", data, &resp) 25 | return 26 | } 27 | 28 | func MarkMsgAsRead(data types.MarkMsgAsReadData) (resp types.Response, err error) { 29 | err = gocqhttp.PostRequest("/mark_msg_as_read", data, &resp) 30 | return 31 | } 32 | 33 | func SendGroupForwardMsg(data types.SendGroupForwardMsgData) (resp types.SendGroupForwardMsgResp, err error) { 34 | err = gocqhttp.PostRequest("/send_group_forward_msg", data, &resp) 35 | return 36 | } 37 | 38 | func SendGroupMsg(data types.SendGroupMsgData) (resp types.SendGroupMsgResp, err error) { 39 | err = gocqhttp.PostRequest("/send_group_msg", data, &resp) 40 | return 41 | } 42 | 43 | func SendPrivateForwardMsg(data types.SendPrivateForwardMsgData) (resp types.SendPrivateForwardMsgResp, err error) { 44 | err = gocqhttp.PostRequest("/send_private_forward_msg", data, &resp) 45 | return 46 | } 47 | 48 | func SendPrivateMsg(data types.SendPrivateMsgData) (resp types.SendPrivateMsgResp, err error) { 49 | err = gocqhttp.PostRequest("/send_private_msg", data, &resp) 50 | return 51 | } 52 | -------------------------------------------------------------------------------- /pkg/gocqhttp/common/voice.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "github.com/Elyart-Network/NyaBot/pkg/gocqhttp" 5 | "github.com/Elyart-Network/NyaBot/pkg/gocqhttp/types" 6 | ) 7 | 8 | func GetRecord(data types.GetRecordData) (resp types.GetRecordResp, err error) { 9 | err = gocqhttp.PostRequest("/get_record", data, &resp) 10 | return 11 | } 12 | 13 | func CanSendRecord() (resp types.CanSendRecordResp, err error) { 14 | err = gocqhttp.GetRequest("/can_send_record", &resp) 15 | return 16 | } 17 | -------------------------------------------------------------------------------- /pkg/gocqhttp/cqcode/cqcode.go: -------------------------------------------------------------------------------- 1 | package cqcode 2 | 3 | import ( 4 | "github.com/Elyart-Network/NyaBot/pkg/gocqhttp/types" 5 | ) 6 | 7 | func Face(data types.FaceData) string { 8 | return "[CQ:face,id=" + data.ID + "]" 9 | } 10 | 11 | func Record(data types.RecordData) string { 12 | return "[CQ:record,file=" + data.File + ",magic=" + data.Magic + ",cache=" + data.Cache + ",proxy=" + data.Proxy + ",timeout=" + data.Timeout + "]" 13 | } 14 | 15 | func Video(data types.VideoData) string { 16 | return "[CQ:video,file=" + data.File + "]" 17 | } 18 | 19 | func VideoFull(data types.VideoData) string { 20 | return "[CQ:video,file=" + data.File + ",cover=" + data.Cover + ",c=" + data.Thread + "]" 21 | } 22 | 23 | func At(data types.AtData) string { 24 | return "[CQ:at,qq=" + data.QQ + ",name=" + data.Name + "]" 25 | } 26 | 27 | func Rps() string { 28 | return "[CQ:rps]" 29 | } 30 | 31 | func Dice() string { 32 | return "[CQ:dice]" 33 | } 34 | 35 | func Shake() string { 36 | return "[CQ:shake]" 37 | } 38 | 39 | func Anonymous() string { 40 | return "[CQ:anonymous]" 41 | } 42 | 43 | func Share(data types.ShareData) string { 44 | return "[CQ:share,url=" + data.URL + ",title=" + data.Title + "]" 45 | } 46 | 47 | func ShareFull(data types.ShareData) string { 48 | return "[CQ:share,url=" + data.URL + ",title=" + data.Title + ",content=" + data.Content + ",image=" + data.Image + "]" 49 | } 50 | 51 | func Contact(data types.ContactData) string { 52 | return "[CQ:contact,type=" + data.Type + ",id=" + data.ID + "]" 53 | } 54 | 55 | func Location(data types.LocationData) string { 56 | return "[CQ:location,lat=" + data.Lat + ",lon=" + data.Lon + "]" 57 | } 58 | 59 | func LocationFull(data types.LocationData) string { 60 | return "[CQ:location,lat=" + data.Lat + ",lon=" + data.Lon + ",title=" + data.Title + ",content=" + data.Content + "]" 61 | } 62 | 63 | func Music(data types.MusicData) string { 64 | return "[CQ:music,type=" + data.Type + ",id=" + data.ID + "]" 65 | } 66 | 67 | func MusicFull(data types.MusicData) string { 68 | return "[CQ:music,type=" + data.Type + ",id=" + data.ID + ",audio=" + data.Audio + ",title=" + data.Title + ",content=" + data.Content + ",image=" + data.Image + "]" 69 | } 70 | 71 | func Image(data types.ImageData) string { 72 | return "[CQ:image,file=" + data.File + ",url=" + data.Url + "]" 73 | } 74 | 75 | func ImageFull(data types.ImageData) string { 76 | return "[CQ:image,file=" + data.File + ",type=" + data.Type + ",subType=" + data.SubType + ",url=" + data.Url + ",cache=" + data.Cache + ",id=" + data.ID + ",c=" + data.Thread + "]" 77 | } 78 | 79 | func Reply(data types.ReplyData) string { 80 | return "[CQ:reply,id=" + data.ID + "]" 81 | } 82 | 83 | func ReplyFull(data types.ReplyData) string { 84 | return "[CQ:reply,id=" + data.ID + ",text=" + data.Text + ",qq=" + data.QQ + ",time=" + data.Time + ",seq=" + data.Seq + "]" 85 | } 86 | 87 | func RedBag(data types.RedBagData) string { 88 | return "[CQ:redbag,title=" + data.Title + "]" 89 | } 90 | 91 | func Poke(data types.PokeData) string { 92 | return "[CQ:poke,qq=" + data.QQ + "]" 93 | } 94 | 95 | func Gift(data types.GiftData) string { 96 | return "[CQ:gift,qq=" + data.QQ + ",id=" + data.ID + "]" 97 | } 98 | 99 | func Forward(data types.ForwardData) string { 100 | return "[CQ:forward,id=" + data.ID + "]" 101 | } 102 | 103 | func Xml(data types.XmlData) string { 104 | return "[CQ:xml,data=" + data.Data + ",resid=" + data.ResID + "]" 105 | } 106 | 107 | func Json(data types.JsonData) string { 108 | return "[CQ:json,data=" + data.Data + "]" 109 | } 110 | 111 | func JsonRich(data types.JsonData) string { 112 | return "[CQ:json,data=" + data.Data + ",resid=" + data.ResID + "]" 113 | } 114 | 115 | func CardImage(data types.CardImageData) string { 116 | return "[CQ:cardimage,file=" + data.File + "]" 117 | } 118 | 119 | func CardImageFull(data types.CardImageData) string { 120 | return "[CQ:cardimage,file=" + data.File + ",minwidth=" + data.MinWidth + ",minheight=" + data.MinHeight + ",maxwidth=" + data.MaxWidth + ",maxheight=" + data.MaxHeight + ",source=" + data.Source + ",icon=" + data.Icon + "]" 121 | } 122 | 123 | func Tts(data types.TtsData) string { 124 | return "[CQ:tts,text=" + data.Text + "]" 125 | } 126 | -------------------------------------------------------------------------------- /pkg/gocqhttp/cqcode/decode.go: -------------------------------------------------------------------------------- 1 | package cqcode 2 | 3 | import ( 4 | log "github.com/sirupsen/logrus" 5 | "regexp" 6 | "strings" 7 | ) 8 | 9 | func Find(msg string) []string { 10 | regex := regexp.MustCompile(`\[CQ:.*?]`) 11 | if regex == nil { 12 | log.Debug("[CqCode] Error compiling CQ code regex") 13 | return nil 14 | } 15 | result := regex.FindAllString(msg, -1) 16 | return result 17 | } 18 | 19 | func Decode(code string) map[string]string { 20 | // Return nil if code is not a CQ code 21 | if !strings.HasPrefix(code, "[CQ:") { 22 | log.Debug("[CqCode] Error compiling CQ code: " + code) 23 | return nil 24 | } 25 | 26 | // Trim prefix and suffix then split key-value pairs 27 | trimPrefix := strings.TrimPrefix(code, "[CQ:") 28 | trimSuffix := strings.TrimSuffix(trimPrefix, "]") 29 | splitKV := strings.Split(trimSuffix, ",") 30 | var codeMap = make(map[string]string) 31 | 32 | // Read type and store in map 33 | if strings.Contains(splitKV[0], "=") { 34 | log.Debug("[CqCode] Error reading CQ code type: " + code) 35 | return nil 36 | } 37 | codeMap["code-type"] = splitKV[0] // type 38 | 39 | // Read key-value pairs and store in map 40 | for _, v := range splitKV { 41 | if !strings.Contains(v, "=") { 42 | continue 43 | } 44 | split := strings.Split(v, "=") 45 | if len(split) != 2 { 46 | log.Debug("[CqCode] Error splitting CQ code key-value pairs: " + code) 47 | return nil 48 | } 49 | codeMap[split[0]] = split[1] 50 | } 51 | 52 | // Return map 53 | return codeMap 54 | } 55 | -------------------------------------------------------------------------------- /pkg/gocqhttp/friend/actions.go: -------------------------------------------------------------------------------- 1 | package friend 2 | 3 | import ( 4 | "github.com/Elyart-Network/NyaBot/pkg/gocqhttp" 5 | "github.com/Elyart-Network/NyaBot/pkg/gocqhttp/types" 6 | ) 7 | 8 | func DeleteFriend(data types.DeleteFriendData) (resp types.Response, err error) { 9 | err = gocqhttp.PostRequest("/delete_friend", data, &resp) 10 | return 11 | } 12 | 13 | func DeleteUnidirectionalFriend(data types.DeleteUnidirectionalFriendData) (resp types.Response, err error) { 14 | err = gocqhttp.PostRequest("/delete_unidirectional_friend", data, &resp) 15 | return 16 | } 17 | -------------------------------------------------------------------------------- /pkg/gocqhttp/friend/message.go: -------------------------------------------------------------------------------- 1 | package friend 2 | 3 | import ( 4 | "github.com/Elyart-Network/NyaBot/pkg/gocqhttp" 5 | "github.com/Elyart-Network/NyaBot/pkg/gocqhttp/types" 6 | ) 7 | 8 | func GetStrangerInfo(data types.GetStrangerInfoData) (resp types.GetStrangerInfoResp, err error) { 9 | err = gocqhttp.PostRequest("/get_stranger_info", data, &resp) 10 | return 11 | } 12 | 13 | func GetFriendList() (resp types.GetFriendListResp, err error) { 14 | err = gocqhttp.GetRequest("/get_friend_list", &resp) 15 | return 16 | } 17 | 18 | func GetUnidirectionalFriendList() (resp types.GetUnidirectionalFriendListResp, err error) { 19 | err = gocqhttp.GetRequest("/get_unidirectional_friend_list", &resp) 20 | return 21 | } 22 | -------------------------------------------------------------------------------- /pkg/gocqhttp/group/actions.go: -------------------------------------------------------------------------------- 1 | package group 2 | 3 | import ( 4 | "github.com/Elyart-Network/NyaBot/pkg/gocqhttp" 5 | "github.com/Elyart-Network/NyaBot/pkg/gocqhttp/types" 6 | ) 7 | 8 | func SetGroupBan(data types.SetGroupBanData) (resp types.Response, err error) { 9 | err = gocqhttp.PostRequest("/set_group_ban", data, &resp) 10 | return 11 | } 12 | 13 | func SetGroupWholeBan(data types.SetGroupWholeBanData) (resp types.Response, err error) { 14 | err = gocqhttp.PostRequest("/set_group_whole_ban", data, &resp) 15 | return 16 | } 17 | 18 | func SetGroupAnonymousBan(data types.SetGroupAnonymousBanData) (resp types.Response, err error) { 19 | err = gocqhttp.PostRequest("/set_group_anonymous_ban", data, &resp) 20 | return 21 | } 22 | 23 | func SetEssenceMsg(data types.SetEssenceMsgData) (resp types.Response, err error) { 24 | err = gocqhttp.PostRequest("/set_essence_msg", data, &resp) 25 | return 26 | } 27 | 28 | func DeleteEssenceMsg(data types.DeleteEssenceMsgData) (resp types.Response, err error) { 29 | err = gocqhttp.PostRequest("/delete_essence_msg", data, &resp) 30 | return 31 | } 32 | 33 | func SendGroupSign(data types.SendGroupSignData) (resp types.Response, err error) { 34 | err = gocqhttp.PostRequest("/send_group_sign", data, &resp) 35 | return 36 | } 37 | 38 | func SetGroupAnonymous(data types.SetGroupAnonymousData) (resp types.Response, err error) { 39 | err = gocqhttp.PostRequest("/set_group_anonymous", data, &resp) 40 | return 41 | } 42 | 43 | func SendGroupNotice(data types.SendGroupNoticeData) (resp types.Response, err error) { 44 | err = gocqhttp.PostRequest("/send_group_notice", data, &resp) 45 | return 46 | } 47 | 48 | func GetGroupNotice(data types.GetGroupNoticeData) (resp types.GetGroupNoticeResp, err error) { 49 | err = gocqhttp.PostRequest("/get_group_notice", data, &resp) 50 | return 51 | } 52 | 53 | func SetGroupKick(data types.SetGroupKickData) (resp types.Response, err error) { 54 | err = gocqhttp.PostRequest("/set_group_kick", data, &resp) 55 | return 56 | } 57 | 58 | func SetGroupLeave(data types.SetGroupLeaveData) (resp types.Response, err error) { 59 | err = gocqhttp.PostRequest("/set_group_leave", data, &resp) 60 | return 61 | } 62 | -------------------------------------------------------------------------------- /pkg/gocqhttp/group/message.go: -------------------------------------------------------------------------------- 1 | package group 2 | 3 | import ( 4 | "github.com/Elyart-Network/NyaBot/pkg/gocqhttp" 5 | "github.com/Elyart-Network/NyaBot/pkg/gocqhttp/types" 6 | ) 7 | 8 | func GetGroupInfo(data types.GetGroupInfoData) (resp types.GetGroupInfoResp, err error) { 9 | err = gocqhttp.PostRequest("/get_group_info", data, &resp) 10 | return 11 | } 12 | 13 | func GetGroupList(data types.GetGroupListData) (resp types.GetGroupListResp, err error) { 14 | err = gocqhttp.PostRequest("/get_group_list", data, &resp) 15 | return 16 | } 17 | 18 | func GetGroupMemberInfo(data types.GetGroupMemberInfoData) (resp types.GetGroupMemberInfoResp, err error) { 19 | err = gocqhttp.PostRequest("/get_group_member_info", data, &resp) 20 | return 21 | } 22 | 23 | func GetGroupMemberList(data types.GetGroupMemberListData) (resp types.GetGroupMemberListResp, err error) { 24 | err = gocqhttp.PostRequest("/get_group_member_list", data, &resp) 25 | return 26 | } 27 | 28 | func GetGroupHonorInfo(data types.GetGroupHonorInfoData) (resp types.GetGroupHonorInfoResp, err error) { 29 | err = gocqhttp.PostRequest("/get_group_honor_info", data, &resp) 30 | return 31 | } 32 | 33 | func GetGroupSystemMsg() (resp types.GetGroupSystemMsgResp, err error) { 34 | err = gocqhttp.GetRequest("/get_group_system_msg", &resp) 35 | return 36 | } 37 | 38 | func GetEssenceMsgList(data types.GetEssenceMsgListData) (resp types.GetEssenceMsgListResp, err error) { 39 | err = gocqhttp.PostRequest("/get_essence_msg_list", data, &resp) 40 | return 41 | } 42 | 43 | func GetGroupAtAllRemain(data types.GetGroupAtAllRemainData) (resp types.GetGroupAtAllRemainResp, err error) { 44 | err = gocqhttp.PostRequest("/get_group_at_all_remain", data, &resp) 45 | return 46 | } 47 | -------------------------------------------------------------------------------- /pkg/gocqhttp/group/settings.go: -------------------------------------------------------------------------------- 1 | package group 2 | 3 | import ( 4 | "github.com/Elyart-Network/NyaBot/pkg/gocqhttp" 5 | "github.com/Elyart-Network/NyaBot/pkg/gocqhttp/types" 6 | ) 7 | 8 | func SetGroupName(data types.SetGroupNameData) (resp types.Response, err error) { 9 | err = gocqhttp.PostRequest("/set_group_name", data, &resp) 10 | return 11 | } 12 | 13 | func SetGroupPortrait(data types.SetGroupPortraitData) (resp types.Response, err error) { 14 | err = gocqhttp.PostRequest("/set_group_portrait", data, &resp) 15 | return 16 | } 17 | 18 | func SetGroupAdmin(data types.SetGroupAdminData) (resp types.Response, err error) { 19 | err = gocqhttp.PostRequest("/set_group_admin", data, &resp) 20 | return 21 | } 22 | 23 | func SetGroupCard(data types.SetGroupCardData) (resp types.Response, err error) { 24 | err = gocqhttp.PostRequest("/set_group_card", data, &resp) 25 | return 26 | } 27 | 28 | func SetGroupSpecialTitle(data types.SetGroupSpecialTitleData) (resp types.Response, err error) { 29 | err = gocqhttp.PostRequest("/set_group_special_title", data, &resp) 30 | return 31 | } 32 | -------------------------------------------------------------------------------- /pkg/gocqhttp/request.go: -------------------------------------------------------------------------------- 1 | package gocqhttp 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/Elyart-Network/NyaBot/config" 6 | "github.com/Elyart-Network/NyaBot/pkg/gocqhttp/websocket" 7 | "github.com/Elyart-Network/NyaBot/utils" 8 | log "github.com/sirupsen/logrus" 9 | "math/rand" 10 | "time" 11 | ) 12 | 13 | func GetRequest(Endpoint string, RespStruct any) (err error) { 14 | // Delay 15 | time.Sleep(time.Duration(rand.Intn(config.Get("gocqhttp.delay").(int))) * time.Millisecond) 16 | // Websocket Reverse 17 | if websocket.WsSendRequest(Endpoint, nil, &RespStruct) { 18 | return 19 | } 20 | // HTTP Reverse 21 | CqHttpHost := config.Get("gocqhttp.host_url").(string) 22 | request, err := utils.GetRequest(CqHttpHost+Endpoint, "") 23 | if err != nil { 24 | return err 25 | } 26 | err = json.Unmarshal(request, &RespStruct) 27 | if err != nil { 28 | return err 29 | } 30 | log.Debug("[GoCqHttp] HTTP GET REQUEST sent! @Endpoint:", Endpoint, " @Response:", RespStruct) 31 | return 32 | } 33 | 34 | func PostRequest(Endpoint string, Params any, RespStruct any) (err error) { 35 | // Delay 36 | time.Sleep(time.Duration(rand.Intn(config.Get("gocqhttp.delay").(int))) * time.Millisecond) 37 | // Websocket Reverse 38 | if websocket.WsSendRequest(Endpoint, Params, &RespStruct) { 39 | return 40 | } 41 | // HTTP Reverse 42 | CqHttpHost := config.Get("gocqhttp.host_url").(string) 43 | request, err := utils.PostRequest(CqHttpHost+Endpoint, Params) 44 | if err != nil { 45 | return err 46 | } 47 | err = json.Unmarshal(request, &RespStruct) 48 | if err != nil { 49 | return err 50 | } 51 | log.Debug("[GoCqHttp] HTTP POST REQUEST sent! @Endpoint:", Endpoint, " @Params:", Params, " @Response:", RespStruct) 52 | return 53 | } 54 | -------------------------------------------------------------------------------- /pkg/gocqhttp/system/account.go: -------------------------------------------------------------------------------- 1 | package system 2 | 3 | import ( 4 | "github.com/Elyart-Network/NyaBot/pkg/gocqhttp" 5 | "github.com/Elyart-Network/NyaBot/pkg/gocqhttp/types" 6 | ) 7 | 8 | func GetModelShow(data types.GetModelShowData) (resp types.GetModelShowResp, err error) { 9 | err = gocqhttp.PostRequest("/_get_model_show", data, &resp) 10 | return 11 | } 12 | 13 | func SetModelShow(data types.SetModelShowData) (resp types.Response, err error) { 14 | err = gocqhttp.PostRequest("/_set_model_show", data, &resp) 15 | return 16 | } 17 | 18 | func GetLoginInfo() (resp types.GetLoginInfoResp, err error) { 19 | err = gocqhttp.GetRequest("/get_login_info", &resp) 20 | return 21 | } 22 | 23 | func GetOnlineClients(data types.GetOnlineClientsData) (resp types.GetOnlineClientsResp, err error) { 24 | err = gocqhttp.PostRequest("/get_online_clients", data, &resp) 25 | return 26 | } 27 | 28 | func QiDianGetAccountInfo() (resp types.Response, err error) { 29 | err = gocqhttp.GetRequest("/qidian_get_account_info", &resp) 30 | return 31 | } 32 | 33 | func SetQQProfile(data types.SetQQProfileData) (resp types.Response, err error) { 34 | err = gocqhttp.PostRequest("/set_qq_profile", data, &resp) 35 | return 36 | } 37 | -------------------------------------------------------------------------------- /pkg/gocqhttp/system/internal.go: -------------------------------------------------------------------------------- 1 | package system 2 | 3 | import ( 4 | "github.com/Elyart-Network/NyaBot/pkg/gocqhttp" 5 | "github.com/Elyart-Network/NyaBot/pkg/gocqhttp/types" 6 | ) 7 | 8 | func GetCookies(data types.GetCookiesData) (resp types.GetCookiesResp, err error) { 9 | err = gocqhttp.PostRequest("/get_cookies", data, &resp) 10 | return 11 | } 12 | 13 | func GetCsrfToken() (resp types.GetCsrfTokenResp, err error) { 14 | err = gocqhttp.GetRequest("/get_csrf_token", &resp) 15 | return 16 | } 17 | 18 | func GetCredentials() (resp types.GetCredentialsResp, err error) { 19 | err = gocqhttp.GetRequest("/get_credentials", &resp) 20 | return 21 | } 22 | 23 | func GetVersionInfo() (resp types.GetVersionInfoResp, err error) { 24 | err = gocqhttp.GetRequest("/get_version_info", &resp) 25 | return 26 | } 27 | 28 | func GetStatus() (resp types.GetStatusResp, err error) { 29 | err = gocqhttp.GetRequest("/get_status", &resp) 30 | return 31 | } 32 | 33 | func SetRestart(data types.SetRestartData) (resp types.Response, err error) { 34 | err = gocqhttp.PostRequest("/set_restart", data, &resp) 35 | return 36 | } 37 | 38 | func CleanCache() (resp types.Response, err error) { 39 | err = gocqhttp.GetRequest("/clean_cache", &resp) 40 | return 41 | } 42 | 43 | func ReloadEventFilter(data types.ReloadEventFilterData) (resp types.Response, err error) { 44 | err = gocqhttp.PostRequest("/reload_event_filter", data, &resp) 45 | return 46 | } 47 | 48 | func DownloadFile(data types.DownloadFileData) (resp types.DownloadFileResp, err error) { 49 | err = gocqhttp.PostRequest("/download_file", data, &resp) 50 | return 51 | } 52 | 53 | func CheckUrlSafely(data types.CheckUrlSafelyData) (resp types.CheckUrlSafelyResp, err error) { 54 | err = gocqhttp.PostRequest("/check_url_safely", data, &resp) 55 | return 56 | } 57 | 58 | func GetWordSlices(data types.GetWordSlicesData) (resp types.GetWordSlicesResp, err error) { 59 | err = gocqhttp.PostRequest("/get_word_slices", data, &resp) 60 | return 61 | } 62 | 63 | func HandleQuickOperation(data types.HandleQuickOperationData) (resp types.Response, err error) { 64 | err = gocqhttp.PostRequest("/handle_quick_operation", data, &resp) 65 | return 66 | } 67 | -------------------------------------------------------------------------------- /pkg/gocqhttp/system/requests.go: -------------------------------------------------------------------------------- 1 | package system 2 | 3 | import ( 4 | "github.com/Elyart-Network/NyaBot/pkg/gocqhttp" 5 | "github.com/Elyart-Network/NyaBot/pkg/gocqhttp/types" 6 | ) 7 | 8 | func SetFriendAddRequest(data types.SetFriendAddRequestData) (resp types.Response, err error) { 9 | err = gocqhttp.PostRequest("/set_friend_add_request", data, &resp) 10 | return 11 | } 12 | 13 | func SetGroupAddRequest(data types.SetGroupAddRequestData) (resp types.Response, err error) { 14 | err = gocqhttp.PostRequest("/set_group_add_request", data, &resp) 15 | return 16 | } 17 | -------------------------------------------------------------------------------- /pkg/gocqhttp/types/account.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | type GetModelShowData struct { 4 | Model string `json:"model"` 5 | } 6 | 7 | type SetModelShowData struct { 8 | Model string `json:"model"` 9 | ModelShow string `json:"model_show"` 10 | } 11 | 12 | type GetOnlineClientsData struct { 13 | NoCache bool `json:"no_cache"` 14 | } 15 | 16 | type SetQQProfileData struct { 17 | Nickname string `json:"nickname"` 18 | Company string `json:"company"` 19 | Email string `json:"email"` 20 | College string `json:"college"` 21 | PersonalNote string `json:"personal_note"` 22 | } 23 | 24 | type GetModelShowResp struct { 25 | Response 26 | Data struct { 27 | Variants []VariantsObject `json:"variants"` 28 | } `json:"data"` 29 | } 30 | 31 | type GetLoginInfoResp struct { 32 | Response 33 | Data struct { 34 | UserID int64 `json:"user_id"` 35 | Nickname string `json:"nickname"` 36 | } `json:"data"` 37 | } 38 | 39 | type GetOnlineClientsResp struct { 40 | Response 41 | Data struct { 42 | Clients []DeviceObject `json:"clients"` 43 | } `json:"data"` 44 | } 45 | 46 | type VariantsObject struct { 47 | ModelShow string `json:"model_show"` 48 | NeedPay bool `json:"need_pay"` 49 | } 50 | 51 | type DeviceObject struct { 52 | AppID int64 `json:"app_id"` 53 | DeviceName string `json:"device_name"` 54 | DeviceKind string `json:"device_kind"` 55 | } 56 | -------------------------------------------------------------------------------- /pkg/gocqhttp/types/actions.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "github.com/Elyart-Network/NyaBot/pkg/gocqhttp/callback" 5 | ) 6 | 7 | // Friend Actions 8 | type DeleteFriendData struct { 9 | UserID int64 `json:"user_id"` 10 | } 11 | 12 | type DeleteUnidirectionalFriendData struct { 13 | UserID int64 `json:"user_id"` 14 | } 15 | 16 | // Group Actions 17 | type SetGroupBanData struct { 18 | GroupID int64 `json:"group_id"` 19 | UserID int64 `json:"user_id"` 20 | Duration uint32 `json:"duration"` 21 | } 22 | 23 | type SetGroupWholeBanData struct { 24 | GroupID int64 `json:"group_id"` 25 | Enable bool `json:"enable"` 26 | } 27 | 28 | type SetGroupAnonymousBanData struct { 29 | GroupID int64 `json:"group_id"` 30 | Anonymous callback.AnonymousObject `json:"anonymous"` 31 | Flag string `json:"flag"` 32 | Duration uint32 `json:"duration"` 33 | } 34 | 35 | type SetEssenceMsgData struct { 36 | MessageID int32 `json:"message_id"` 37 | } 38 | 39 | type DeleteEssenceMsgData struct { 40 | MessageID int32 `json:"message_id"` 41 | } 42 | 43 | type SendGroupSignData struct { 44 | GroupID int64 `json:"group_id"` 45 | } 46 | 47 | type SetGroupAnonymousData struct { 48 | GroupID int64 `json:"group_id"` 49 | Enable bool `json:"enable"` 50 | } 51 | 52 | type SendGroupNoticeData struct { 53 | GroupID int64 `json:"group_id"` 54 | Content string `json:"content"` 55 | Image string `json:"image"` 56 | } 57 | 58 | type GetGroupNoticeData struct { 59 | GroupID int64 `json:"group_id"` 60 | } 61 | 62 | type SetGroupKickData struct { 63 | GroupID int64 `json:"group_id"` 64 | UserID int64 `json:"user_id"` 65 | Reject bool `json:"reject_add_request"` 66 | } 67 | 68 | type SetGroupLeaveData struct { 69 | GroupID int64 `json:"group_id"` 70 | IsDismiss bool `json:"is_dismiss"` 71 | } 72 | 73 | type GetGroupNoticeResp struct { 74 | Response 75 | Data struct { 76 | SenderID int64 `json:"sender_id"` 77 | PublishTime int64 `json:"publish_time"` 78 | Message MessageObject `json:"message"` 79 | } `json:"data"` 80 | } 81 | 82 | type MessageObject struct { 83 | Text string `json:"text"` 84 | Images []ImageObject `json:"images"` 85 | } 86 | 87 | type ImageObject struct { 88 | Height string `json:"height"` 89 | Width string `json:"width"` 90 | Id string `json:"id"` 91 | } 92 | -------------------------------------------------------------------------------- /pkg/gocqhttp/types/cqcode.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | type FaceData struct { 4 | ID string 5 | } 6 | 7 | type RecordData struct { 8 | File string 9 | Magic string 10 | Cache string 11 | Proxy string 12 | Timeout string 13 | } 14 | 15 | type VideoData struct { 16 | File string 17 | Cover string 18 | Thread string 19 | } 20 | 21 | type AtData struct { 22 | QQ string 23 | Name string 24 | } 25 | 26 | type ShareData struct { 27 | URL string 28 | Title string 29 | Content string 30 | Image string 31 | } 32 | 33 | type ContactData struct { 34 | Type string 35 | ID string 36 | } 37 | 38 | type LocationData struct { 39 | Lat string 40 | Lon string 41 | Title string 42 | Content string 43 | } 44 | 45 | type MusicData struct { 46 | Type string 47 | ID string 48 | Audio string 49 | Title string 50 | Content string 51 | Image string 52 | } 53 | 54 | type ImageData struct { 55 | File string 56 | Type string 57 | SubType string 58 | Url string 59 | Cache string 60 | ID string 61 | Thread string 62 | } 63 | 64 | type ReplyData struct { 65 | ID string 66 | Text string 67 | QQ string 68 | Time string 69 | Seq string 70 | } 71 | 72 | type RedBagData struct { 73 | Title string 74 | } 75 | 76 | type PokeData struct { 77 | QQ string 78 | } 79 | 80 | type GiftData struct { 81 | QQ string 82 | ID string 83 | } 84 | 85 | type ForwardData struct { 86 | ID string 87 | } 88 | 89 | type XmlData struct { 90 | Data string 91 | ResID string 92 | } 93 | 94 | type JsonData struct { 95 | Data string 96 | ResID string 97 | } 98 | 99 | type CardImageData struct { 100 | File string 101 | MinWidth string 102 | MaxWidth string 103 | MinHeight string 104 | MaxHeight string 105 | Source string 106 | Icon string 107 | } 108 | 109 | type TtsData struct { 110 | Text string 111 | } 112 | -------------------------------------------------------------------------------- /pkg/gocqhttp/types/file.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | type UploadGroupFileData struct { 4 | GroupID int64 `json:"group_id"` 5 | File string `json:"file"` 6 | Name string `json:"name"` 7 | Folder string `json:"folder"` 8 | } 9 | 10 | type DeleteGroupFileData struct { 11 | GroupID int64 `json:"group_id"` 12 | FileID string `json:"file_id"` 13 | BusID int32 `json:"busid"` 14 | } 15 | 16 | type CreateGroupFileFolderData struct { 17 | GroupID int64 `json:"group_id"` 18 | Name string `json:"name"` 19 | ParentID string `json:"parent_id"` 20 | } 21 | 22 | type DeleteGroupFolderData struct { 23 | GroupID int64 `json:"group_id"` 24 | FolderID string `json:"folder_id"` 25 | } 26 | 27 | type GetGroupFileSystemInfoData struct { 28 | GroupID int64 `json:"group_id"` 29 | } 30 | 31 | type GetGroupRootFilesData struct { 32 | GroupID int64 `json:"group_id"` 33 | } 34 | 35 | type GetGroupFilesByFolderData struct { 36 | GroupID int64 `json:"group_id"` 37 | FolderID string `json:"folder_id"` 38 | } 39 | 40 | type GetGroupFileUrlData struct { 41 | GroupID int64 `json:"group_id"` 42 | FileID string `json:"file_id"` 43 | BusID int32 `json:"busid"` 44 | } 45 | 46 | type UploadPrivateFileData struct { 47 | UserID int64 `json:"user_id"` 48 | File string `json:"file"` 49 | Name string `json:"name"` 50 | } 51 | 52 | type GetGroupFileSystemInfoResp struct { 53 | Response 54 | Data struct { 55 | FileCount int32 `json:"file_count"` 56 | LimitCount int32 `json:"limit_count"` 57 | UsedSpace int64 `json:"used_space"` 58 | TotalSpace int64 `json:"total_space"` 59 | } `json:"data"` 60 | } 61 | 62 | type GetGroupRootFilesResp struct { 63 | Response 64 | Data struct { 65 | Files []FileObject `json:"files"` 66 | Folders []FolderObject `json:"folders"` 67 | } `json:"data"` 68 | } 69 | 70 | type GetGroupFilesByFolderResp struct { 71 | Response 72 | Data struct { 73 | Files []FileObject `json:"files"` 74 | Folders []FolderObject `json:"folders"` 75 | } `json:"data"` 76 | } 77 | 78 | type GetGroupFileUrlResp struct { 79 | Response 80 | Data struct { 81 | Url string `json:"url"` 82 | } `json:"data"` 83 | } 84 | 85 | type FileObject struct { 86 | GroupID int32 `json:"group_id"` 87 | FileID string `json:"file_id"` 88 | FileName string `json:"file_name"` 89 | BusID int32 `json:"busid"` 90 | FileSize int64 `json:"file_size"` 91 | UploadTime int64 `json:"upload_time"` 92 | DeadTime int64 `json:"dead_time"` 93 | ModifyTime int64 `json:"modify_time"` 94 | DownloadTimes int32 `json:"download_times"` 95 | Uploader int64 `json:"uploader"` 96 | UploaderName string `json:"uploader_name"` 97 | } 98 | 99 | type FolderObject struct { 100 | GroupID int32 `json:"group_id"` 101 | FolderID string `json:"folder_id"` 102 | FolderName string `json:"folder_name"` 103 | CreateTime int64 `json:"create_time"` 104 | Creator int64 `json:"creator"` 105 | CreatorName string `json:"creator_name"` 106 | TotalFileCount int32 `json:"total_file_count"` 107 | } 108 | -------------------------------------------------------------------------------- /pkg/gocqhttp/types/forward.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | type ForwardIdNode struct { 4 | Type string `json:"type"` 5 | Data ForwardIdData `json:"data"` 6 | } 7 | 8 | type ForwardIdData struct { 9 | Id string `json:"id"` 10 | } 11 | 12 | type ForwardCustomNode struct { 13 | Type string `json:"type"` 14 | Data ForwardCustomData `json:"data"` 15 | } 16 | 17 | type ForwardCustomData struct { 18 | Name string `json:"name"` 19 | Uin string `json:"uin"` 20 | Content string `json:"content"` 21 | Seq string `json:"seq"` 22 | Time string `json:"time"` 23 | } 24 | -------------------------------------------------------------------------------- /pkg/gocqhttp/types/image.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | type GetImageData struct { 4 | File string `json:"file"` 5 | } 6 | 7 | type OcrImageData struct { 8 | Image string `json:"image"` 9 | } 10 | 11 | type GetImageResp struct { 12 | Response 13 | Data struct { 14 | Size int32 `json:"size"` 15 | FileName string `json:"filename"` 16 | Url string `json:"url"` 17 | } `json:"data"` 18 | } 19 | 20 | type CanSendImageResp struct { 21 | Response 22 | Data struct { 23 | Yes bool `json:"yes"` 24 | } `json:"data"` 25 | } 26 | 27 | type OcrImageResp struct { 28 | Response 29 | Data struct { 30 | Texts []TextDetectionObject `json:"texts"` 31 | Language string `json:"language"` 32 | } `json:"data"` 33 | } 34 | 35 | type TextDetectionObject struct { 36 | Text string `json:"text"` 37 | Confidence int32 `json:"confidence"` 38 | Coordinates []any `json:"coordinates"` 39 | } 40 | -------------------------------------------------------------------------------- /pkg/gocqhttp/types/internal.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | type GetCookiesData struct { 4 | Domain string `json:"domain"` 5 | } 6 | 7 | type GetCredentialsData struct { 8 | Domain string `json:"domain"` 9 | } 10 | 11 | type SetRestartData struct { 12 | Delay int `json:"delay"` 13 | } 14 | 15 | type ReloadEventFilterData struct { 16 | File string `json:"file"` 17 | } 18 | 19 | type DownloadFileData struct { 20 | Url string `json:"url"` 21 | ThreadCount int32 `json:"thread_count"` 22 | Headers map[string]string `json:"headers"` 23 | } 24 | 25 | type CheckUrlSafelyData struct { 26 | Url string `json:"url"` 27 | } 28 | 29 | type GetWordSlicesData struct { 30 | Content string `json:"content"` 31 | } 32 | 33 | type HandleQuickOperationData struct { 34 | Context any `json:"context"` 35 | Operation any `json:"operation"` 36 | } 37 | 38 | type GetCookiesResp struct { 39 | Response 40 | Data struct { 41 | Cookies string `json:"cookies"` 42 | } `json:"data"` 43 | } 44 | 45 | type GetCsrfTokenResp struct { 46 | Response 47 | Data struct { 48 | Token int `json:"token"` 49 | } `json:"data"` 50 | } 51 | 52 | type GetCredentialsResp struct { 53 | Response 54 | Data struct { 55 | Cookies string `json:"cookies"` 56 | CsrfToken int32 `json:"csrf_token"` 57 | } `json:"data"` 58 | } 59 | 60 | type GetVersionInfoResp struct { 61 | Response 62 | Data struct { 63 | AppName string `json:"app_name"` 64 | AppVersion string `json:"app_version"` 65 | AppFullName string `json:"app_full_name"` 66 | ProtocolVersion string `json:"protocol_version"` 67 | CoolqEdition string `json:"coolq_edition"` 68 | CoolqDirectory string `json:"coolq_directory"` 69 | GoCqHttp bool `json:"go-cqhttp"` 70 | PluginVersion string `json:"plugin_version"` 71 | PluginBuildNumber int `json:"plugin_build_number"` 72 | PluginBuildConfiguration string `json:"plugin_build_configuration"` 73 | RuntimeVersion string `json:"runtime_version"` 74 | RuntimeOs string `json:"runtime_os"` 75 | Version string `json:"version"` 76 | Protocol int `json:"protocol"` 77 | } `json:"data"` 78 | } 79 | 80 | type GetStatusResp struct { 81 | Response 82 | Data struct { 83 | AppInitialized bool `json:"app_initialized"` 84 | AppEnabled bool `json:"app_enabled"` 85 | PluginsGood bool `json:"plugins_good"` 86 | AppGood bool `json:"app_good"` 87 | Online bool `json:"online"` 88 | Good bool `json:"good"` 89 | Stat StatisticsObject `json:"stat"` 90 | } `json:"data"` 91 | } 92 | 93 | type StatisticsObject struct { 94 | PacketReceived uint64 `json:"PacketReceived"` 95 | PacketSent uint64 `json:"PacketSent"` 96 | PacketLost uint32 `json:"PacketLost"` 97 | MessageReceived uint64 `json:"MessageReceived"` 98 | MessageSent uint64 `json:"MessageSent"` 99 | DisconnectTimes uint32 `json:"DisconnectTimes"` 100 | LostTimes uint32 `json:"LostTimes"` 101 | LastMessageTime int64 `json:"LastMessageTime"` 102 | } 103 | 104 | type DownloadFileResp struct { 105 | Response 106 | Data struct { 107 | File string `json:"file"` 108 | } `json:"data"` 109 | } 110 | 111 | type CheckUrlSafelyResp struct { 112 | Response 113 | Data struct { 114 | Level int `json:"level"` 115 | } `json:"data"` 116 | } 117 | 118 | type GetWordSlicesResp struct { 119 | Response 120 | Data struct { 121 | Slices []string `json:"slices"` 122 | } `json:"data"` 123 | } 124 | -------------------------------------------------------------------------------- /pkg/gocqhttp/types/message.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | // Common Message 4 | type DeleteMsgData struct { 5 | MessageID int32 `json:"message_id"` 6 | } 7 | 8 | type GetForwardMsgData struct { 9 | MessageID string `json:"message_id"` 10 | } 11 | 12 | type GetGroupMsgHistoryData struct { 13 | MessageSeq int64 `json:"message_seq"` 14 | GroupID int64 `json:"group_id"` 15 | } 16 | 17 | type GetMsgData struct { 18 | MessageID int32 `json:"message_id"` 19 | } 20 | 21 | type MarkMsgAsReadData struct { 22 | MessageID int32 `json:"message_id"` 23 | } 24 | 25 | type SendGroupForwardMsgData struct { 26 | GroupID int64 `json:"group_id"` 27 | Messages any `json:"messages"` 28 | } 29 | 30 | type SendGroupMsgData struct { 31 | GroupID int64 `json:"group_id"` 32 | Message string `json:"message"` 33 | AutoEscape bool `json:"auto_escape"` 34 | } 35 | 36 | type SendPrivateForwardMsgData struct { 37 | UserID int64 `json:"user_id"` 38 | Messages any `json:"messages"` 39 | } 40 | 41 | type SendPrivateMsgData struct { 42 | UserID int64 `json:"user_id"` 43 | Message string `json:"message"` 44 | GroupID int64 `json:"group_id"` 45 | AutoEscape bool `json:"auto_escape"` 46 | } 47 | 48 | type GetForwardMsgResp struct { 49 | Response 50 | Data struct { 51 | Messages []ForwardMessagesObject `json:"messages"` 52 | } `json:"data"` 53 | } 54 | 55 | type GetGroupMsgHistoryResp struct { 56 | Response 57 | Data struct { 58 | Messages []any `json:"messages"` 59 | } `json:"data"` 60 | } 61 | 62 | type GetMsgResp struct { 63 | Response 64 | Data struct { 65 | Group bool `json:"group"` 66 | GroupID int64 `json:"group_id"` 67 | MessageID int32 `json:"message_id"` 68 | RealID int32 `json:"real_id"` 69 | MessageType string `json:"message_type"` 70 | Sender SenderObject `json:"sender"` 71 | Time int `json:"time"` 72 | Message any `json:"message"` 73 | RawMessage any `json:"raw_message"` 74 | } `json:"data"` 75 | } 76 | 77 | type SendGroupForwardMsgResp struct { 78 | Response 79 | Data struct { 80 | MessageID int64 `json:"message_id"` 81 | ForwardID string `json:"forward_id"` 82 | } `json:"data"` 83 | } 84 | 85 | type SendGroupMsgResp struct { 86 | Response 87 | Data struct { 88 | MessageID int32 `json:"message_id"` 89 | } `json:"data"` 90 | } 91 | 92 | type SendPrivateForwardMsgResp struct { 93 | Response 94 | Data struct { 95 | MessageID int64 `json:"message_id"` 96 | ForwardID string `json:"forward_id"` 97 | } `json:"data"` 98 | } 99 | 100 | type SendPrivateMsgResp struct { 101 | Response 102 | Data struct { 103 | MessageID int32 `json:"message_id"` 104 | } `json:"data"` 105 | } 106 | 107 | type ForwardMessagesObject struct { 108 | Content string `json:"content"` 109 | Sender SenderObject `json:"sender"` 110 | Time int `json:"time"` 111 | } 112 | 113 | type SenderObject struct { 114 | Nickname string `json:"nickname"` 115 | UserID int64 `json:"user_id"` 116 | } 117 | 118 | // Friend Message 119 | type GetStrangerInfoData struct { 120 | UserID int64 `json:"user_id"` 121 | NoCache bool `json:"no_cache"` 122 | } 123 | 124 | type GetStrangerInfoResp struct { 125 | Response 126 | Data struct { 127 | UserID int64 `json:"user_id"` 128 | Nickname string `json:"nickname"` 129 | Sex string `json:"sex"` 130 | Age int32 `json:"age"` 131 | Qid string `json:"qid"` 132 | Level int32 `json:"level"` 133 | LoginDays int32 `json:"login_days"` 134 | } `json:"data"` 135 | } 136 | 137 | type GetFriendListResp struct { 138 | Response 139 | Data []struct { 140 | UserID int64 `json:"user_id"` 141 | Nickname string `json:"nickname"` 142 | Remark string `json:"remark"` 143 | } `json:"data"` 144 | } 145 | 146 | type GetUnidirectionalFriendListResp struct { 147 | Response 148 | Data []struct { 149 | UserID int64 `json:"user_id"` 150 | Nickname string `json:"nickname"` 151 | Source string `json:"source"` 152 | } `json:"data"` 153 | } 154 | 155 | // Group Message 156 | type GetGroupInfoData struct { 157 | GroupID int64 `json:"group_id"` 158 | NoCache bool `json:"no_cache"` 159 | } 160 | 161 | type GetGroupListData struct { 162 | NoCache bool `json:"no_cache"` 163 | } 164 | 165 | type GetGroupMemberInfoData struct { 166 | GroupID int64 `json:"group_id"` 167 | UserID int64 `json:"user_id"` 168 | NoCache bool `json:"no_cache"` 169 | } 170 | 171 | type GetGroupMemberListData struct { 172 | GroupID int64 `json:"group_id"` 173 | NoCache bool `json:"no_cache"` 174 | } 175 | 176 | type GetGroupHonorInfoData struct { 177 | GroupID int64 `json:"group_id"` 178 | Type string `json:"type"` 179 | } 180 | 181 | type GetEssenceMsgListData struct { 182 | GroupID int64 `json:"group_id"` 183 | } 184 | 185 | type GetGroupAtAllRemainData struct { 186 | GroupID int64 `json:"group_id"` 187 | } 188 | 189 | type GetGroupInfoResp struct { 190 | Response 191 | Data GroupInfoObject `json:"data"` 192 | } 193 | 194 | type GetGroupListResp struct { 195 | Response 196 | Data []GroupInfoObject `json:"data"` 197 | } 198 | 199 | type GetGroupMemberInfoResp struct { 200 | Response 201 | Data GroupMemberInfoObject `json:"data"` 202 | } 203 | 204 | type GetGroupMemberListResp struct { 205 | Response 206 | Data []GroupMemberInfoObject `json:"data"` 207 | } 208 | 209 | type GetGroupHonorInfoResp struct { 210 | Response 211 | Data struct { 212 | GroupID int64 `json:"group_id"` 213 | CurrentTalkative CurrentTalkativeObject `json:"current_talkative"` 214 | TalkativeList []HonorListObject `json:"talkative_list"` 215 | PerformerList []HonorListObject `json:"performer_list"` 216 | LegendList []HonorListObject `json:"legend_list"` 217 | StrongNewbieList []HonorListObject `json:"strong_newbie_list"` 218 | EmotionList []HonorListObject `json:"emotion_list"` 219 | } `json:"data"` 220 | } 221 | 222 | type GetGroupSystemMsgResp struct { 223 | Response 224 | Data struct { 225 | InvitedRequests []InvitedRequestObject `json:"invited_requests"` 226 | JoinRequests []JoinRequestObject `json:"join_requests"` 227 | } `json:"data"` 228 | } 229 | 230 | type GetEssenceMsgListResp struct { 231 | Response 232 | Data []struct { 233 | SenderID int64 `json:"sender_id"` 234 | SenderNick string `json:"sender_nick"` 235 | SenderTime int64 `json:"sender_time"` 236 | OperatorID int64 `json:"operator_id"` 237 | OperatorNick string `json:"operator_nick"` 238 | OperatorTime int64 `json:"operator_time"` 239 | MessageID int32 `json:"message_id"` 240 | } `json:"data"` 241 | } 242 | 243 | type GetGroupAtAllRemainResp struct { 244 | Response 245 | Data struct { 246 | CanAtAll bool `json:"can_at_all"` 247 | RemainAtAllCountForGroup int16 `json:"remain_at_all_count_for_group"` 248 | RemainAtAllCountForUin int16 `json:"remain_at_all_count_for_uin"` 249 | } `json:"data"` 250 | } 251 | 252 | type GroupInfoObject struct { 253 | GroupID int64 `json:"group_id"` 254 | GroupName string `json:"group_name"` 255 | GroupMemo string `json:"group_memo"` 256 | GroupCreateTime uint32 `json:"group_create_time"` 257 | GroupLevel uint32 `json:"group_level"` 258 | MemberCount int32 `json:"member_count"` 259 | MaxMemberCount int32 `json:"max_member_count"` 260 | } 261 | 262 | type GroupMemberInfoObject struct { 263 | GroupID int64 `json:"group_id"` 264 | UserID int64 `json:"user_id"` 265 | Nickname string `json:"nickname"` 266 | Card string `json:"card"` 267 | Sex string `json:"sex"` 268 | Age int32 `json:"age"` 269 | Area string `json:"area"` 270 | JoinTime int32 `json:"join_time"` 271 | LastSentTime int32 `json:"last_sent_time"` 272 | Level string `json:"level"` 273 | Role string `json:"role"` 274 | Unfriendly bool `json:"unfriendly"` 275 | Title string `json:"title"` 276 | TitleExpireTime int64 `json:"title_expire_time"` 277 | CardChangeable bool `json:"card_changeable"` 278 | ShutUpTimestamp int64 `json:"shut_up_timestamp"` 279 | } 280 | 281 | type CurrentTalkativeObject struct { 282 | UserID int64 `json:"user_id"` 283 | Nickname string `json:"nickname"` 284 | Avatar string `json:"avatar"` 285 | DayCount int32 `json:"day_count"` 286 | } 287 | 288 | type HonorListObject struct { 289 | UserID int64 `json:"user_id"` 290 | Nickname string `json:"nickname"` 291 | Avatar string `json:"avatar"` 292 | Description string `json:"description"` 293 | } 294 | 295 | type InvitedRequestObject struct { 296 | RequestID int64 `json:"request_id"` 297 | InvitorUin int64 `json:"invitor_uin"` 298 | InvitorNick string `json:"invitor_nick"` 299 | GroupID int64 `json:"group_id"` 300 | GroupName string `json:"group_name"` 301 | Checked bool `json:"checked"` 302 | Actor int64 `json:"actor"` 303 | } 304 | 305 | type JoinRequestObject struct { 306 | RequestID int64 `json:"request_id"` 307 | RequesterUin int64 `json:"requester_uin"` 308 | RequesterNick string `json:"requester_nick"` 309 | Message string `json:"message"` 310 | GroupID int64 `json:"group_id"` 311 | GroupName string `json:"group_name"` 312 | Checked bool `json:"checked"` 313 | Actor int64 `json:"actor"` 314 | } 315 | -------------------------------------------------------------------------------- /pkg/gocqhttp/types/requests.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | type SetFriendAddRequestData struct { 4 | Flag string `json:"flag"` 5 | Approve bool `json:"approve"` 6 | Remark string `json:"remark"` 7 | } 8 | 9 | type SetGroupAddRequestData struct { 10 | Flag string `json:"flag"` 11 | SubType string `json:"sub_type"` 12 | Approve bool `json:"approve"` 13 | Reason string `json:"reason"` 14 | } 15 | -------------------------------------------------------------------------------- /pkg/gocqhttp/types/response.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | type Response struct { 4 | Status string `json:"status"` 5 | RetCode int `json:"retcode"` 6 | Msg string `json:"msg"` 7 | Wording string `json:"wording"` 8 | Echo string `json:"echo"` 9 | } 10 | -------------------------------------------------------------------------------- /pkg/gocqhttp/types/settings.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | type SetGroupNameData struct { 4 | GroupID int64 `json:"group_id"` 5 | GroupName string `json:"group_name"` 6 | } 7 | 8 | type SetGroupPortraitData struct { 9 | GroupID int64 `json:"group_id"` 10 | File string `json:"file"` 11 | Cache int `json:"cache"` 12 | } 13 | 14 | type SetGroupAdminData struct { 15 | GroupID int64 `json:"group_id"` 16 | UserID int64 `json:"user_id"` 17 | Enable bool `json:"enable"` 18 | } 19 | 20 | type SetGroupCardData struct { 21 | GroupID int64 `json:"group_id"` 22 | UserID int64 `json:"user_id"` 23 | Card string `json:"card"` 24 | } 25 | 26 | type SetGroupSpecialTitleData struct { 27 | GroupID int64 `json:"group_id"` 28 | UserID int64 `json:"user_id"` 29 | SpecialTitle string `json:"special_title"` 30 | Duration uint32 `json:"duration"` 31 | } 32 | -------------------------------------------------------------------------------- /pkg/gocqhttp/types/voice.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | type GetRecordData struct { 4 | File string `json:"file"` 5 | OutFormat string `json:"out_format"` 6 | } 7 | 8 | type GetRecordResp struct { 9 | Response 10 | Data struct { 11 | File string `json:"file"` 12 | } `json:"data"` 13 | } 14 | 15 | type CanSendRecordResp struct { 16 | Response 17 | Data struct { 18 | Yes bool `json:"yes"` 19 | } `json:"data"` 20 | } 21 | -------------------------------------------------------------------------------- /pkg/gocqhttp/websocket/connector.go: -------------------------------------------------------------------------------- 1 | package websocket 2 | 3 | import ( 4 | "github.com/Elyart-Network/NyaBot/config" 5 | "github.com/Elyart-Network/NyaBot/pkg/gocqhttp/callback" 6 | "github.com/gorilla/websocket" 7 | "log" 8 | "net/http" 9 | ) 10 | 11 | type CqCallback func(callback callback.Full) 12 | 13 | var up = websocket.Upgrader{ 14 | CheckOrigin: func(r *http.Request) bool { 15 | return true 16 | }, 17 | } 18 | 19 | func wsHandler(ws *websocket.Conn, call CqCallback) { 20 | for { 21 | // Read Message 22 | _, wsContext, err := ws.ReadMessage() 23 | if err != nil { 24 | log.Println("[WebSocket] ws read error: ", err) 25 | break 26 | } 27 | // Encode Message to wsActionData. 28 | resp, isResp, err := wsResponseEncode(wsContext) 29 | if err != nil { 30 | log.Println("[WebSocket] ws response encode error: ", err) 31 | break 32 | } 33 | // Send callback to plugin functions. 34 | if !isResp { 35 | data, err := callback.Encode(wsContext, true) 36 | if err != nil { 37 | log.Println("[WebSocket] callback encode error: ", err) 38 | break 39 | } 40 | call(data) 41 | } 42 | // Send request. 43 | go func() { 44 | for data := range requestChan { 45 | err := ws.WriteJSON(data) 46 | if err != nil { 47 | log.Println("[WebSocket] ws write json error: ", err) 48 | break 49 | } 50 | } 51 | }() 52 | // Send response. 53 | if isResp { 54 | responseChan <- resp 55 | } 56 | } 57 | } 58 | 59 | func Client(callback CqCallback) { 60 | dialer := websocket.DefaultDialer 61 | wsHost := config.Get("gocqhttp.host_url").(string) 62 | ws, _, err := dialer.Dial(wsHost, nil) 63 | if err != nil { 64 | log.Println("[WebSocket] ws dial error: ", err) 65 | return 66 | } 67 | defer func(ws *websocket.Conn) { 68 | err := ws.Close() 69 | if err != nil { 70 | log.Println("[WebSocket] ws close error: ", err) 71 | return 72 | } 73 | }(ws) 74 | wsHandler(ws, callback) 75 | } 76 | 77 | func Server(w http.ResponseWriter, r *http.Request, callback CqCallback) { 78 | ws, err := up.Upgrade(w, r, nil) 79 | if err != nil { 80 | log.Println("[WebSocket] ws upgrade error: ", err) 81 | return 82 | } 83 | defer func(ws *websocket.Conn) { 84 | err := ws.Close() 85 | if err != nil { 86 | log.Println("[WebSocket] ws close error: ", err) 87 | return 88 | } 89 | }(ws) 90 | wsHandler(ws, callback) 91 | } 92 | -------------------------------------------------------------------------------- /pkg/gocqhttp/websocket/request.go: -------------------------------------------------------------------------------- 1 | package websocket 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/Elyart-Network/NyaBot/config" 6 | "log" 7 | "strconv" 8 | "strings" 9 | "time" 10 | ) 11 | 12 | type wsRequestData struct { 13 | Action string `json:"action"` 14 | Params any `json:"params"` 15 | Echo string `json:"echo"` 16 | } 17 | 18 | var requestChan = make(chan wsRequestData) 19 | 20 | func WsSendRequest(Endpoint string, Params any, RespStruct any) bool { 21 | if !config.Get("gocqhttp.enable").(bool) || !config.Get("gocqhttp.enable_ws").(bool) { 22 | return false 23 | } 24 | // Prepare request data. 25 | Endpoint = strings.TrimPrefix(Endpoint, "/") 26 | timeUnixNano := strconv.FormatInt(time.Now().UnixNano(), 10) 27 | echo := "nyabot_" + Endpoint + "_" + timeUnixNano 28 | requestData := wsRequestData{ 29 | Action: Endpoint, 30 | Params: Params, 31 | Echo: echo, 32 | } 33 | // Send request. 34 | requestChan <- requestData 35 | // Wait for response. 36 | for data := range responseChan { 37 | if data.Echo == echo { 38 | // Decode response data from wsResponseData to RespStruct. 39 | jsonData, err := json.Marshal(data) 40 | err = json.Unmarshal(jsonData, &RespStruct) 41 | if err != nil { 42 | log.Println("[WebSocket] ws response decode error: ", err) 43 | return true 44 | } 45 | return true 46 | } 47 | } 48 | return true 49 | } 50 | -------------------------------------------------------------------------------- /pkg/gocqhttp/websocket/response.go: -------------------------------------------------------------------------------- 1 | package websocket 2 | 3 | import ( 4 | "encoding/json" 5 | "strings" 6 | ) 7 | 8 | type wsResponseData struct { 9 | Status string `json:"status"` 10 | RetCode int `json:"retcode"` 11 | Msg string `json:"msg"` 12 | Wording string `json:"wording"` 13 | Echo string `json:"echo"` 14 | Data any `json:"data"` 15 | PostType string `json:"post_type"` 16 | } 17 | 18 | var responseChan = make(chan wsResponseData) 19 | 20 | func wsResponseEncode(wsContext []byte) (resp wsResponseData, isResp bool, err error) { 21 | // Encode Message to wsActionData. 22 | err = json.Unmarshal(wsContext, &resp) 23 | if resp.PostType == "meta_event" { 24 | return resp, false, nil 25 | } 26 | if echo := resp.Echo; echo != "" && strings.HasPrefix(echo, "nyabot_") { 27 | return resp, true, err 28 | } 29 | return wsResponseData{}, false, err 30 | } 31 | -------------------------------------------------------------------------------- /pkg/plugin/entry.go: -------------------------------------------------------------------------------- 1 | package plugin 2 | 3 | import ( 4 | "github.com/Elyart-Network/NyaBot/pkg/gocqhttp/callback" 5 | "github.com/Elyart-Network/NyaBot/pkg/gocqhttp/websocket" 6 | "github.com/Elyart-Network/NyaBot/pkg/webhook" 7 | "github.com/gin-gonic/gin" 8 | log "github.com/sirupsen/logrus" 9 | ) 10 | 11 | func WhEntry(ctx *gin.Context) { 12 | data := webhook.Data{} 13 | err := ctx.BindJSON(&data) 14 | if err != nil { 15 | log.Error("[Plugin] Webhook callback decode error: ", err) 16 | return 17 | } 18 | log.Debug("[Entry] Received WebHook Callback. @Data:", data) 19 | WhCallBack(data) 20 | } 21 | 22 | func CqEntry(ctx *gin.Context) { 23 | data, err := callback.Encode(ctx, false) 24 | if err != nil { 25 | log.Error("[Plugin] GoCqHttp callback decode error: ", err) 26 | return 27 | } 28 | log.Debug("[Entry] Received CoolQ Callback. @Data:", data) 29 | CqCallBack(data) 30 | } 31 | func CqWebSocketForward() { 32 | go websocket.Client(CqCallBack) 33 | } 34 | func CqWebSocketReverse(ctx *gin.Context) { 35 | go websocket.Server(ctx.Writer, ctx.Request, CqCallBack) 36 | } 37 | func DiscordEntry(ctx *gin.Context) {} 38 | func TelegramEntry(ctx *gin.Context) {} 39 | func SlackEntry(ctx *gin.Context) {} 40 | -------------------------------------------------------------------------------- /pkg/plugin/plugin.go: -------------------------------------------------------------------------------- 1 | package plugin 2 | 3 | import ( 4 | "github.com/Elyart-Network/NyaBot/pkg/gocqhttp/callback" 5 | "github.com/Elyart-Network/NyaBot/pkg/webhook" 6 | log "github.com/sirupsen/logrus" 7 | ) 8 | 9 | var plugins = make(map[string]any) 10 | 11 | func WhRegister(plugin WhPlugin) { 12 | plugins[plugin.(CommonInfo).Info().Name] = plugin 13 | log.Debug("[Nya-Plugin] Plugin ", plugin.(CommonInfo).Info().Name, " registered.") 14 | } 15 | 16 | func CqRegister(plugin CqPlugin) { 17 | plugins[plugin.(CommonInfo).Info().Name] = plugin 18 | log.Debug("[Nya-Plugin] Plugin ", plugin.(CommonInfo).Info().Name, " registered.") 19 | } 20 | 21 | func WhCallBack(callback webhook.Data) { 22 | // Send callback to plugin functions. 23 | for _, value := range plugins { 24 | value := value 25 | go func() { 26 | if value.(CommonInfo).Info().Type == "Webhook" { 27 | value.(WhPlugin).Receive(callback) 28 | } 29 | }() 30 | } 31 | } 32 | 33 | func CqCallBack(callback callback.Full) { 34 | // Send callback to plugin functions. 35 | for _, value := range plugins { 36 | value := value 37 | go func() { 38 | if value.(CommonInfo).Info().Type == "GoCqHttp" { 39 | switch callback.PostType { 40 | case "message": 41 | log.Debug("[Plugin]", "(GoCqHttp)", "{"+value.(CommonInfo).Info().Name+"}", " Message Event Received.") 42 | value.(CqPlugin).Message(callback) 43 | case "request": 44 | log.Debug("[Plugin]", "(GoCqHttp)", "{"+value.(CommonInfo).Info().Name+"}", " Request Event Received.") 45 | value.(CqPlugin).Request(callback) 46 | case "notice": 47 | log.Debug("[Plugin]", "(GoCqHttp)", "{"+value.(CommonInfo).Info().Name+"}", " Notice Event Received.") 48 | value.(CqPlugin).Notice(callback) 49 | case "meta_event": 50 | log.Debug("[Plugin]", "(GoCqHttp)", "{"+value.(CommonInfo).Info().Name+"}", " Meta Event Received.") 51 | value.(CqPlugin).MetaEvent(callback) 52 | } 53 | } 54 | }() 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /pkg/plugin/types.go: -------------------------------------------------------------------------------- 1 | package plugin 2 | 3 | import ( 4 | "github.com/Elyart-Network/NyaBot/pkg/gocqhttp/callback" 5 | "github.com/Elyart-Network/NyaBot/pkg/webhook" 6 | ) 7 | 8 | type InfoStruct struct { 9 | Name string 10 | Version string 11 | Author string 12 | Description string 13 | License string 14 | Homepage string 15 | Repository string 16 | Type string 17 | } 18 | 19 | type CommonInfo interface { 20 | Info() InfoStruct 21 | } 22 | 23 | type WhPlugin interface { 24 | CommonInfo 25 | Receive(callback webhook.Data) 26 | } 27 | 28 | type CqPlugin interface { 29 | CommonInfo 30 | Message(callback callback.Full) 31 | Request(callback callback.Full) 32 | Notice(callback callback.Full) 33 | MetaEvent(callback callback.Full) 34 | } 35 | -------------------------------------------------------------------------------- /pkg/webhook/types.go: -------------------------------------------------------------------------------- 1 | package webhook 2 | 3 | type Data struct { 4 | Source Source `json:"source"` 5 | Target Target `json:"target"` 6 | Message Message `json:"message"` 7 | Callback bool `json:"callback"` 8 | TimeStamp int64 `json:"time_stamp"` 9 | } 10 | 11 | type Source struct { 12 | // "GoCqHttp"/"Mirai"/"OneBot"/"Telegram"/"Discord"/"Slack" 13 | Platform string `json:"platform"` 14 | Addition any `json:"addition"` 15 | } 16 | 17 | type Target struct { 18 | GoCqHttp 19 | } 20 | 21 | type GoCqHttp struct { 22 | // "Group"/"Private" 23 | Type string `json:"type"` 24 | // Group ID/ Private ID 25 | ID int64 `json:"id"` 26 | } 27 | 28 | type Message struct { 29 | Type string `json:"type"` 30 | Content string `json:"content"` 31 | Addition any `json:"addition"` 32 | } 33 | -------------------------------------------------------------------------------- /plugins/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SNENET/NyaBot/f0a7c6e76114660ac1628fe9e023efac1121bcbe/plugins/.gitkeep -------------------------------------------------------------------------------- /scripts/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SNENET/NyaBot/f0a7c6e76114660ac1628fe9e023efac1121bcbe/scripts/.gitkeep -------------------------------------------------------------------------------- /server/entry.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | "github.com/Elyart-Network/NyaBot/config" 5 | "github.com/Elyart-Network/NyaBot/logger" 6 | "github.com/Elyart-Network/NyaBot/pkg/plugin" 7 | "github.com/gin-gonic/gin" 8 | log "github.com/sirupsen/logrus" 9 | "google.golang.org/grpc" 10 | "net/http" 11 | "strings" 12 | ) 13 | 14 | func GinServer() http.Handler { 15 | server := gin.New() 16 | server.Use(logger.Gin(), gin.Recovery()) 17 | server.GET("/", func(c *gin.Context) { 18 | c.JSON(404, gin.H{ 19 | "status": "Not Found", 20 | }) 21 | }) 22 | server.GET("/health", func(c *gin.Context) { 23 | log.Debug("[Gin] Health Checked!") 24 | c.JSON(200, gin.H{ 25 | "status": "OK", 26 | }) 27 | }) 28 | server.POST("/webhook", plugin.WhEntry) 29 | if config.Get("gocqhttp.enable").(bool) { 30 | if config.Get("gocqhttp.enable_ws").(bool) { 31 | switch strings.HasPrefix(config.Get("gocqhttp.host_url").(string), "ws") { 32 | case true: 33 | plugin.CqWebSocketForward() 34 | case false: 35 | server.GET("/api/gocqhttp", plugin.CqWebSocketReverse) 36 | } 37 | } 38 | server.POST("/api/gocqhttp", plugin.CqEntry) 39 | } 40 | return server 41 | } 42 | 43 | func RPCServer() http.Handler { 44 | server := gin.New() 45 | rpc := grpc.NewServer() 46 | server.Use(logger.Gin(), gin.Recovery()) 47 | server.Use(func(ctx *gin.Context) { 48 | if ctx.Request.ProtoMajor == 2 && 49 | strings.HasPrefix(ctx.GetHeader("Content-Type"), "application/grpc") { 50 | ctx.Status(http.StatusOK) 51 | rpc.ServeHTTP(ctx.Writer, ctx.Request) 52 | ctx.Abort() 53 | return 54 | } 55 | ctx.Next() 56 | }) 57 | server.GET("/", func(c *gin.Context) { 58 | c.JSON(404, gin.H{ 59 | "status": "Not Found", 60 | }) 61 | }) 62 | server.GET("/health", func(c *gin.Context) { 63 | log.Debug("[RPC] Health Checked!") 64 | c.JSON(200, gin.H{ 65 | "status": "OK", 66 | }) 67 | }) 68 | return server 69 | } 70 | -------------------------------------------------------------------------------- /server/server.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | "github.com/Elyart-Network/NyaBot/config" 5 | "github.com/gin-gonic/gin" 6 | log "github.com/sirupsen/logrus" 7 | "golang.org/x/sync/errgroup" 8 | "net/http" 9 | "time" 10 | ) 11 | 12 | var g errgroup.Group 13 | 14 | func Start() { 15 | ServerPort := config.Get("server.listen_port").(string) 16 | RpcPort := config.Get("server.rpc_port").(string) 17 | DebugMode := config.Get("server.debug_mode").(bool) 18 | 19 | if DebugMode { 20 | gin.SetMode(gin.DebugMode) 21 | } else { 22 | gin.SetMode(gin.ReleaseMode) 23 | } 24 | 25 | gs := &http.Server{ 26 | Addr: ":" + ServerPort, 27 | Handler: GinServer(), 28 | ReadTimeout: 5 * time.Second, 29 | WriteTimeout: 10 * time.Second, 30 | } 31 | 32 | rpc := &http.Server{ 33 | Addr: ":" + RpcPort, 34 | Handler: RPCServer(), 35 | ReadTimeout: 5 * time.Second, 36 | WriteTimeout: 10 * time.Second, 37 | } 38 | 39 | g.Go(func() error { 40 | return gs.ListenAndServe() 41 | }) 42 | 43 | g.Go(func() error { 44 | if RpcPort != "" { 45 | return rpc.ListenAndServe() 46 | } 47 | return nil 48 | }) 49 | 50 | if err := g.Wait(); err != nil { 51 | log.Panicln(err) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /utils/request.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "io" 7 | "net/http" 8 | ) 9 | 10 | func GetRequest(url string, params string) ([]byte, error) { 11 | Request, err := http.Get(url + params) 12 | if err != nil { 13 | return nil, err 14 | } 15 | defer func(Body io.ReadCloser) { 16 | err = Body.Close() 17 | if err != nil { 18 | return 19 | } 20 | }(Request.Body) 21 | Context, err := io.ReadAll(Request.Body) 22 | if err != nil { 23 | return nil, err 24 | } 25 | return Context, nil 26 | } 27 | 28 | func PostRequest(url string, params any) ([]byte, error) { 29 | ByteSlice, err := json.Marshal(params) 30 | Request, err := http.Post(url, "application/json", bytes.NewBuffer(ByteSlice)) 31 | if err != nil { 32 | return nil, err 33 | } 34 | defer func(Body io.ReadCloser) { 35 | err := Body.Close() 36 | if err != nil { 37 | return 38 | } 39 | }(Request.Body) 40 | Context, err := io.ReadAll(Request.Body) 41 | if err != nil { 42 | return nil, err 43 | } 44 | return Context, nil 45 | } 46 | --------------------------------------------------------------------------------