├── .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 | 
2 |
3 | ### NyaBot v3
4 |
5 | -----
6 |
7 |      
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 | [](#contributors-)
36 |
37 |
38 |
39 |
40 |
41 |
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 | 
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 |
--------------------------------------------------------------------------------