Compare commits
374 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
80352e8601 | |
|
|
99dda61a84 | |
|
|
08c0752803 | |
|
|
ed2b936bf2 | |
|
|
6d7e6c26fc | |
|
|
3d0253523b | |
|
|
76b6ec7d74 | |
|
|
4bc256aba4 | |
|
|
6481b18fcd | |
|
|
63ea13bbde | |
|
|
dda5035c7c | |
|
|
7be4aeb90e | |
|
|
00aa3b5b7b | |
|
|
dae8a96478 | |
|
|
fc0218e754 | |
|
|
770cde41bd | |
|
|
da70405ab3 | |
|
|
c75dd8b95e | |
|
|
1a2661bf41 | |
|
|
106e27f457 | |
|
|
345d120460 | |
|
|
0edba050c3 | |
|
|
d02cceb775 | |
|
|
f334668e4b | |
|
|
b4f721060f | |
|
|
c0b8c7ba63 | |
|
|
2f8d80184b | |
|
|
ff3e032d6d | |
|
|
defbafd9d6 | |
|
|
27c5b3cd3c | |
|
|
5e184badca | |
|
|
b3492e6826 | |
|
|
44b74e468b | |
|
|
4e2f319229 | |
|
|
94e5c784c0 | |
|
|
b1bb1cb734 | |
|
|
e2ebdc0621 | |
|
|
f0e025bec5 | |
|
|
6e5ee4f0e2 | |
|
|
4592681978 | |
|
|
80ab607432 | |
|
|
1ff1347187 | |
|
|
1244feb7de | |
|
|
6c835e371a | |
|
|
1cfb517fc9 | |
|
|
29c05b0af7 | |
|
|
96e1a96f2e | |
|
|
7844e5b121 | |
|
|
c3170ddcb2 | |
|
|
1d698dd28a | |
|
|
11255c71a6 | |
|
|
8a48a54c3a | |
|
|
f3c1ee923a | |
|
|
0c6143086d | |
|
|
95539fbd35 | |
|
|
790d6b75a6 | |
|
|
4dacd672b7 | |
|
|
2e807710bc | |
|
|
7991fd2960 | |
|
|
fb1752b9d7 | |
|
|
3651c31a15 | |
|
|
301817c353 | |
|
|
e1e7e53590 | |
|
|
68e0ee27f2 | |
|
|
a9a9ecc3bd | |
|
|
a2441cdc20 | |
|
|
7cc505daec | |
|
|
aeacecea70 | |
|
|
e94695329c | |
|
|
3967d68ce0 | |
|
|
510b725ade | |
|
|
ef1b2771cd | |
|
|
cf404a97b9 | |
|
|
ab2f5fd1b7 | |
|
|
d6bf91c9fd | |
|
|
892e080d6a | |
|
|
abd00e9ec0 | |
|
|
6366a02900 | |
|
|
1dd87d717e | |
|
|
4ecdda9468 | |
|
|
8a55bfc82b | |
|
|
724c5e6c1f | |
|
|
252fa4683b | |
|
|
aa4b2a8f10 | |
|
|
770a9df5d7 | |
|
|
9cf9876fb9 | |
|
|
395f1f681d | |
|
|
0fc72a86d6 | |
|
|
cc21f69fc0 | |
|
|
16014ff420 | |
|
|
7672b3a638 | |
|
|
963790ed47 | |
|
|
bdc32ec806 | |
|
|
6c57f60170 | |
|
|
40a119cebb | |
|
|
269e8d70f1 | |
|
|
ad24877771 | |
|
|
29f1354cdd | |
|
|
a164def0cd | |
|
|
757062b65f | |
|
|
1bed10c5e5 | |
|
|
8c3db1ce1d | |
|
|
793d306238 | |
|
|
66bd811f05 | |
|
|
7581a17a29 | |
|
|
7c4b0d4649 | |
|
|
af83caeaa4 | |
|
|
41eb5c6367 | |
|
|
ccf1916e4e | |
|
|
8e20f59d01 | |
|
|
b75d6a62ef | |
|
|
e45d802ec8 | |
|
|
2042c11b40 | |
|
|
88ab3a6614 | |
|
|
0ebc447c32 | |
|
|
a6954f8f9e | |
|
|
bda9e235de | |
|
|
e1b2361ef0 | |
|
|
ac3f88c8ce | |
|
|
e9fd3b346d | |
|
|
32bf491219 | |
|
|
5bbb158a7d | |
|
|
e6c51f423c | |
|
|
8165233396 | |
|
|
ecb5656a92 | |
|
|
7e1d876604 | |
|
|
04a01ddb32 | |
|
|
a3e32c3755 | |
|
|
484ee75736 | |
|
|
ab05433289 | |
|
|
4270e77780 | |
|
|
f92fd4767c | |
|
|
038ce10c19 | |
|
|
92afee454c | |
|
|
288f5a0db6 | |
|
|
369264e695 | |
|
|
e34d29b0a4 | |
|
|
7baaa5453a | |
|
|
d618cf0332 | |
|
|
5a3f899772 | |
|
|
f1695df463 | |
|
|
e1ae537386 | |
|
|
5f98ed5651 | |
|
|
f22df7f012 | |
|
|
2320a997b4 | |
|
|
3b46273a3b | |
|
|
1c232b0b83 | |
|
|
5dcd98ab3a | |
|
|
af18019ac3 | |
|
|
8d9a953c53 | |
|
|
6880e033a8 | |
|
|
a83aa1002d | |
|
|
d601fcd210 | |
|
|
2d155b3156 | |
|
|
80cafbc839 | |
|
|
aac77e078a | |
|
|
fc915a0f7c | |
|
|
c9620b64dc | |
|
|
7a650394b0 | |
|
|
381fd3d720 | |
|
|
16885ee880 | |
|
|
928e7f9799 | |
|
|
11f5b02559 | |
|
|
46ad8baa3b | |
|
|
3477c7fad4 | |
|
|
a10d4add52 | |
|
|
09f1a3e38d | |
|
|
b919c068ba | |
|
|
a92a9b97f0 | |
|
|
31d28cbff2 | |
|
|
83282285cb | |
|
|
54f8b03159 | |
|
|
f092e3ac4d | |
|
|
bc1e89280e | |
|
|
2345387422 | |
|
|
8214806a2f | |
|
|
68d9082f96 | |
|
|
586356c18a | |
|
|
0f37e738a7 | |
|
|
d9edd7fa7a | |
|
|
8689f78181 | |
|
|
edef1fd7e0 | |
|
|
ec0c152032 | |
|
|
536b9eb29a | |
|
|
119420932b | |
|
|
fdc3674ff5 | |
|
|
a6ce904059 | |
|
|
3ab7556b38 | |
|
|
c5258b3fb2 | |
|
|
db73c16fe3 | |
|
|
c65ff352df | |
|
|
3e8a2938c0 | |
|
|
766dbcd2fb | |
|
|
a3916a77d0 | |
|
|
945591f695 | |
|
|
f428c0a758 | |
|
|
be079f9b31 | |
|
|
909bf31192 | |
|
|
31ef5ee93b | |
|
|
39cb9bc91f | |
|
|
a803991a42 | |
|
|
aa765e9412 | |
|
|
fb3d2e8e67 | |
|
|
4128347eab | |
|
|
e9f089c6a2 | |
|
|
7b93f3a801 | |
|
|
d8967012d3 | |
|
|
de6b65022a | |
|
|
a28b830523 | |
|
|
d62ef9710d | |
|
|
3e68e4cfa8 | |
|
|
5356efaa73 | |
|
|
9c9a6bf870 | |
|
|
9408bc3831 | |
|
|
ed7e5e68ef | |
|
|
9fed2927fc | |
|
|
47df437cdd | |
|
|
a9c57ef016 | |
|
|
366e9f2821 | |
|
|
e441b554e8 | |
|
|
d0619ca01b | |
|
|
dfe767834b | |
|
|
fff1d93848 | |
|
|
664027a955 | |
|
|
3238116f37 | |
|
|
9d01e83d71 | |
|
|
27858d41e7 | |
|
|
ac8b347cc2 | |
|
|
6560a9a5c2 | |
|
|
b5cd667088 | |
|
|
645106e3e6 | |
|
|
2f0266f3ee | |
|
|
f421dda674 | |
|
|
8e91296373 | |
|
|
05489c8fd7 | |
|
|
067c4ccfe2 | |
|
|
4c9616202d | |
|
|
203559ed82 | |
|
|
61a94ec047 | |
|
|
36b0862db7 | |
|
|
8187c36585 | |
|
|
80602dd4c4 | |
|
|
c5dcd895f4 | |
|
|
e9a95012bd | |
|
|
a05d3b3c7f | |
|
|
f10e46761b | |
|
|
a621cb5ad2 | |
|
|
f720eb509b | |
|
|
1bb639504d | |
|
|
64069034db | |
|
|
eb7a57c215 | |
|
|
62d336e1c0 | |
|
|
71783fe15f | |
|
|
3571772bb1 | |
|
|
8796ef784b | |
|
|
f60328be98 | |
|
|
1b9cf8b3d3 | |
|
|
29e8151420 | |
|
|
4918c54fc6 | |
|
|
65f98fe9de | |
|
|
9755d73b86 | |
|
|
34027a1763 | |
|
|
a88002e3d0 | |
|
|
61b58ec546 | |
|
|
ae38db28f7 | |
|
|
c7dd994543 | |
|
|
8607efd319 | |
|
|
beaecbbb01 | |
|
|
785779d0c5 | |
|
|
3135efa1b0 | |
|
|
db7295465c | |
|
|
07cd44e62d | |
|
|
44e12f0b65 | |
|
|
601e69a384 | |
|
|
4e9e2aa7fc | |
|
|
92e7c94c62 | |
|
|
f360bd750d | |
|
|
be11fcbcef | |
|
|
8e5ecc98ce | |
|
|
8d0617c74e | |
|
|
27ba32888d | |
|
|
a730599641 | |
|
|
3b6b3612fb | |
|
|
4275ef7593 | |
|
|
268d646d71 | |
|
|
7bfe7b5855 | |
|
|
3be19bf29c | |
|
|
16ab36261e | |
|
|
3cb71c1bbf | |
|
|
f10e583aa8 | |
|
|
a3eff32f47 | |
|
|
8daa1612c1 | |
|
|
28edd048ed | |
|
|
b2053f14e4 | |
|
|
35823bee30 | |
|
|
fec81d2bea | |
|
|
d6b1788ae5 | |
|
|
4bc84531d4 | |
|
|
d302535608 | |
|
|
cf7d5d7992 | |
|
|
32b108c314 | |
|
|
f15a1d605b | |
|
|
b83195da91 | |
|
|
42942e8876 | |
|
|
021c475720 | |
|
|
eda29d09a4 | |
|
|
73e3db98db | |
|
|
65ac4802f5 | |
|
|
542935cb8f | |
|
|
54b67296bd | |
|
|
69f04c09a6 | |
|
|
66ec0ff947 | |
|
|
d9e622e37b | |
|
|
9f21e7c1d5 | |
|
|
e651a844f5 | |
|
|
fa554de402 | |
|
|
3a7590ae8d | |
|
|
6ba661c0f8 | |
|
|
e1bae50a04 | |
|
|
f53af2c097 | |
|
|
9a234f50fb | |
|
|
81e0c2a5bf | |
|
|
1ce27b543d | |
|
|
7770efd21a | |
|
|
b9025cf5d1 | |
|
|
b5f01572cc | |
|
|
f17467d451 | |
|
|
420d652e6b | |
|
|
fa0781c353 | |
|
|
9cc3234a61 | |
|
|
6545dc72ac | |
|
|
6cded474a0 | |
|
|
2854365ea5 | |
|
|
756b7af9fe | |
|
|
15507c6cfc | |
|
|
fae1b378a7 | |
|
|
729f333fb0 | |
|
|
798dec54f6 | |
|
|
3e85b9e199 | |
|
|
b244854f2a | |
|
|
77357d27cf | |
|
|
e7898bdd9b | |
|
|
6d45baa4bd | |
|
|
c3d802c2d9 | |
|
|
e192954037 | |
|
|
bb901e8f40 | |
|
|
0543b82a8f | |
|
|
fa1753389e | |
|
|
27a8561448 | |
|
|
1e559ac29d | |
|
|
a1247d9ca4 | |
|
|
63215bba4a | |
|
|
13d21bb22e | |
|
|
2e96977f26 | |
|
|
ec4ec6ab44 | |
|
|
c7be07d22a | |
|
|
c6c6dbe971 | |
|
|
f9b62f6618 | |
|
|
53e04c2fc2 | |
|
|
a13bcd437d | |
|
|
356ab8962b | |
|
|
414bf1589a | |
|
|
a717b4099b | |
|
|
6dbed0199d | |
|
|
a7742b304e | |
|
|
27cd64640f | |
|
|
56cab15a73 | |
|
|
76cb556042 | |
|
|
56514b5e0d | |
|
|
a7b3fc7669 | |
|
|
81a2806641 | |
|
|
ed9a6112d9 | |
|
|
f1534502a2 | |
|
|
e3bc77697b |
|
|
@ -0,0 +1,35 @@
|
|||
version: '1.0'
|
||||
name: pipeline-20250906-release
|
||||
displayName: pipeline-20250906-release
|
||||
triggers:
|
||||
trigger: auto
|
||||
push:
|
||||
branches:
|
||||
precise:
|
||||
- release
|
||||
stages:
|
||||
- name: stage-4863fcf5
|
||||
displayName: 未命名
|
||||
strategy: naturally
|
||||
trigger: auto
|
||||
executor: []
|
||||
steps:
|
||||
- step: build@golang
|
||||
name: build_golang
|
||||
displayName: Golang 构建
|
||||
golangVersion: '1.24'
|
||||
commands:
|
||||
- '# 默认使用goproxy.cn'
|
||||
- export GOPROXY=https://goproxy.cn
|
||||
- '# 输入你的构建命令'
|
||||
- go get
|
||||
- go build
|
||||
artifacts:
|
||||
- name: BUILD_ARTIFACT
|
||||
path:
|
||||
- ./
|
||||
caches:
|
||||
- /go/pkg/mod
|
||||
notify: []
|
||||
strategy:
|
||||
retry: '0'
|
||||
|
|
@ -0,0 +1,661 @@
|
|||
GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
Version 3, 19 November 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU Affero General Public License is a free, copyleft license for
|
||||
software and other kinds of works, specifically designed to ensure
|
||||
cooperation with the community in the case of network server software.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
our General Public Licenses are intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
Developers that use our General Public Licenses protect your rights
|
||||
with two steps: (1) assert copyright on the software, and (2) offer
|
||||
you this License which gives you legal permission to copy, distribute
|
||||
and/or modify the software.
|
||||
|
||||
A secondary benefit of defending all users' freedom is that
|
||||
improvements made in alternate versions of the program, if they
|
||||
receive widespread use, become available for other developers to
|
||||
incorporate. Many developers of free software are heartened and
|
||||
encouraged by the resulting cooperation. However, in the case of
|
||||
software used on network servers, this result may fail to come about.
|
||||
The GNU General Public License permits making a modified version and
|
||||
letting the public access it on a server without ever releasing its
|
||||
source code to the public.
|
||||
|
||||
The GNU Affero General Public License is designed specifically to
|
||||
ensure that, in such cases, the modified source code becomes available
|
||||
to the community. It requires the operator of a network server to
|
||||
provide the source code of the modified version running there to the
|
||||
users of that server. Therefore, public use of a modified version, on
|
||||
a publicly accessible server, gives the public access to the source
|
||||
code of the modified version.
|
||||
|
||||
An older license, called the Affero General Public License and
|
||||
published by Affero, was designed to accomplish similar goals. This is
|
||||
a different license, not a version of the Affero GPL, but Affero has
|
||||
released a new version of the Affero GPL which permits relicensing under
|
||||
this license.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU Affero General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Remote Network Interaction; Use with the GNU General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, if you modify the
|
||||
Program, your modified version must prominently offer all users
|
||||
interacting with it remotely through a computer network (if your version
|
||||
supports such interaction) an opportunity to receive the Corresponding
|
||||
Source of your version by providing access to the Corresponding Source
|
||||
from a network server at no charge, through some standard or customary
|
||||
means of facilitating copying of software. This Corresponding Source
|
||||
shall include the Corresponding Source for any work covered by version 3
|
||||
of the GNU General Public License that is incorporated pursuant to the
|
||||
following paragraph.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the work with which it is combined will remain governed by version
|
||||
3 of the GNU General Public License.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU Affero General Public License from time to time. Such new versions
|
||||
will be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU Affero General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU Affero General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU Affero General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If your software can interact with users remotely through a computer
|
||||
network, you should also make sure that it provides a way for users to
|
||||
get its source. For example, if your program is a web application, its
|
||||
interface could display a "Source" link that leads users to an archive
|
||||
of the code. There are many ways you could offer source, and different
|
||||
solutions will be better for different programs; see section 13 for the
|
||||
specific requirements.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU AGPL, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
78
dao/cid.go
78
dao/cid.go
|
|
@ -3,30 +3,35 @@ package dao
|
|||
import (
|
||||
"fmt"
|
||||
"gorm.io/gorm"
|
||||
"time"
|
||||
)
|
||||
|
||||
type CID struct {
|
||||
gorm.Model
|
||||
Auth_id int `gorm:"column:auth_id"`
|
||||
Name string `gorm:"column:name"`
|
||||
Url string `gorm:"column:url"`
|
||||
Script string `gorm:"column:script"`
|
||||
Token string `gorm:"column:token"` // 用于外部回调
|
||||
Auth_id int `gorm:"column:auth_id"`
|
||||
Name string `gorm:"column:name"`
|
||||
Url string `gorm:"column:url"`
|
||||
Time int `gorm:"column:time"` // 定时任务,单位秒,大于0表示定时任务
|
||||
LastSuccess time.Time `gorm:"column:last_success" json:"last_success"`
|
||||
LastFail time.Time `gorm:"column:last_fail" json:"last_fail"`
|
||||
Script string `gorm:"column:script"`
|
||||
Token string `gorm:"column:token"` // 用于外部回调
|
||||
}
|
||||
|
||||
type CIDRunLog struct {
|
||||
gorm.Model
|
||||
CID_id int `gorm:"column:cid_id"`
|
||||
Auth_id int `form:"column:auth_id"`
|
||||
Script string `gorm:"column:script"`
|
||||
Log string `gorm:"column:log"`
|
||||
Error string `gorm:"column:error"`
|
||||
CID_id int `gorm:"column:cid_id"`
|
||||
Auth_id int `form:"column:auth_id"`
|
||||
Script string `gorm:"column:script"`
|
||||
RunTime float64 `gorm:"column:run_time"`
|
||||
Log string `gorm:"column:log"`
|
||||
Error string `gorm:"column:error"`
|
||||
}
|
||||
|
||||
// CreateCID 创建持续集成、部署
|
||||
func CreateCID(name, url, script, token string, auth_id int) uint {
|
||||
cid := CID{Name: name, Url: url, Script: script, Token: token, Auth_id: auth_id}
|
||||
result := DB.Debug().Create(&cid)
|
||||
func CreateCID(name, url, script, token string, time, auth_id int) uint {
|
||||
cid := CID{Name: name, Url: url, Script: script, Token: token, Auth_id: auth_id, Time: time}
|
||||
result := DB.Create(&cid)
|
||||
if result.Error != nil {
|
||||
return 0
|
||||
}
|
||||
|
|
@ -35,7 +40,7 @@ func CreateCID(name, url, script, token string, auth_id int) uint {
|
|||
|
||||
// DeleteCIDByID 删除持续集成、部署
|
||||
func DeleteCIDByID(id, auth_id int) bool {
|
||||
res := DB.Debug().Model(&CID{}).Where("id = ? and auth_id = ?", id, auth_id).Delete(&CID{})
|
||||
res := DB.Model(&CID{}).Where("id = ? and auth_id = ?", id, auth_id).Delete(&CID{})
|
||||
if res.Error != nil {
|
||||
return false
|
||||
}
|
||||
|
|
@ -45,19 +50,19 @@ func DeleteCIDByID(id, auth_id int) bool {
|
|||
// FindCIDByID 查找持续集成、部署
|
||||
func FindCIDByID(id, auth_id int) CID {
|
||||
var cid CID
|
||||
DB.Debug().Where("id = ? and auth_id = ?", id, auth_id).First(&cid)
|
||||
DB.Where("id = ? and auth_id = ?", id, auth_id).First(&cid)
|
||||
return cid
|
||||
}
|
||||
|
||||
// FindCIDByAuthID 查找持续集成、部署
|
||||
func FindCIDByAuthID(auth_id int) []CID {
|
||||
var cids []CID
|
||||
DB.Debug().Where("auth_id = ?", auth_id).Find(&cids)
|
||||
DB.Where("auth_id = ?", auth_id).Order("created_at").Find(&cids)
|
||||
return cids
|
||||
}
|
||||
|
||||
// UpdateCIDByID 更新持续集成、部署
|
||||
func UpdateCIDByID(id, auth_id int, name, url, script, token string) bool {
|
||||
func UpdateCIDByID(id, auth_id, time int, name, url, script, token string) bool {
|
||||
pd := FindCIDByID(id, auth_id)
|
||||
if pd.ID == 0 {
|
||||
return false
|
||||
|
|
@ -66,7 +71,7 @@ func UpdateCIDByID(id, auth_id int, name, url, script, token string) bool {
|
|||
if token == "" {
|
||||
token = pd.Token
|
||||
}
|
||||
result := DB.Debug().Model(&CID{}).Where("id = ? and auth_id = ?", id, auth_id).Updates(CID{Name: name, Url: url, Script: script, Token: token})
|
||||
result := DB.Model(&CID{}).Where("id = ? and auth_id = ?", id, auth_id).Updates(CID{Name: name, Url: url, Script: script, Token: token, Time: time})
|
||||
if result.Error != nil {
|
||||
return false
|
||||
}
|
||||
|
|
@ -74,9 +79,9 @@ func UpdateCIDByID(id, auth_id int, name, url, script, token string) bool {
|
|||
}
|
||||
|
||||
// CreateRunLog,添加执行日志
|
||||
func CreateRunLog(cid_id, auth_id int, script, log, err string) uint {
|
||||
cidRunLog := CIDRunLog{CID_id: cid_id, Auth_id: auth_id, Log: log, Error: err, Script: script}
|
||||
result := DB.Debug().Create(&cidRunLog)
|
||||
func CreateRunLog(cid_id, auth_id int, script, log, err string, runtime float64) uint {
|
||||
cidRunLog := CIDRunLog{CID_id: cid_id, Auth_id: auth_id, Log: log, Error: err, Script: script, RunTime: runtime}
|
||||
result := DB.Create(&cidRunLog)
|
||||
if result != nil {
|
||||
fmt.Println(err)
|
||||
return 0
|
||||
|
|
@ -86,23 +91,46 @@ func CreateRunLog(cid_id, auth_id int, script, log, err string) uint {
|
|||
|
||||
func FindRunLogByAuthID(auth_id int) []CIDRunLog {
|
||||
var cidRunLogs []CIDRunLog
|
||||
DB.Debug().Where(" auth_id = ?", auth_id).Order("created_at desc").Find(&cidRunLogs)
|
||||
DB.Where(" auth_id = ?", auth_id).Order("created_at desc").Find(&cidRunLogs)
|
||||
return cidRunLogs
|
||||
}
|
||||
|
||||
func FindRunLogByID(auth_id, cid_id int) []CIDRunLog {
|
||||
var cidRunLog []CIDRunLog
|
||||
DB.Debug().Where("cid_id = ? and auth_id = ?", cid_id, auth_id).Order("created_at desc").Find(&cidRunLog)
|
||||
DB.Where("cid_id = ? and auth_id = ?", cid_id, auth_id).Order("created_at desc").Limit(30).Find(&cidRunLog)
|
||||
return cidRunLog
|
||||
}
|
||||
func FindRunLogByCIDLogID(id, auth_id int) []CIDRunLog {
|
||||
var cidRunLogs []CIDRunLog
|
||||
DB.Debug().Where("id = ? and auth_id = ?", id, auth_id).Order("created_at desc").Find(&cidRunLogs)
|
||||
DB.Where("id = ? and auth_id = ?", id, auth_id).Order("created_at desc").Limit(30).Find(&cidRunLogs)
|
||||
return cidRunLogs
|
||||
}
|
||||
|
||||
func FindCIDByIDAndToken(id int, token string) CID {
|
||||
var cid CID
|
||||
DB.Debug().Where("id = ? and token = ?", id, token).First(&cid)
|
||||
DB.Where("id = ? and token = ?", id, token).First(&cid)
|
||||
return cid
|
||||
}
|
||||
|
||||
func FindCIDByTime() []CID {
|
||||
var cids []CID
|
||||
DB.Where("time > 0").Find(&cids)
|
||||
return cids
|
||||
}
|
||||
|
||||
// FindCIDByID 查找持续集成、部署
|
||||
func FindCIDByCID(id uint) CID {
|
||||
var cid CID
|
||||
DB.Where("id = ? ", id).First(&cid)
|
||||
return cid
|
||||
}
|
||||
|
||||
func UpdateLastSuccessByID(id int, time time.Time) error {
|
||||
res := DB.Where("id = ?", id).Update("last_success", time)
|
||||
return res.Error
|
||||
}
|
||||
|
||||
func UpdateLastFailByID(id int, time time.Time) error {
|
||||
res := DB.Where("id = ?", id).Update("last_fail", time)
|
||||
return res.Error
|
||||
}
|
||||
|
|
|
|||
66
dao/db.go
66
dao/db.go
|
|
@ -3,25 +3,43 @@ package dao
|
|||
import (
|
||||
"fmt"
|
||||
"gorm.io/driver/mysql"
|
||||
"gorm.io/driver/postgres"
|
||||
"gorm.io/driver/sqlite"
|
||||
"gorm.io/gorm"
|
||||
"log"
|
||||
"sync"
|
||||
"videoplayer/proto"
|
||||
)
|
||||
|
||||
var DB *gorm.DB
|
||||
|
||||
func Init() error {
|
||||
dsn := proto.MYSQL_DSN
|
||||
var DBMMap = map[uint]*proto.DBValue{}
|
||||
var DBMMapRWMutex = &sync.RWMutex{} //dbm日志
|
||||
|
||||
func Init() error {
|
||||
var db *gorm.DB
|
||||
var err error
|
||||
var dsn string
|
||||
if proto.Config.DB == 0 {
|
||||
dsn = proto.Config.MYSQL_DSN
|
||||
db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{})
|
||||
} else if proto.Config.DB == 1 {
|
||||
dsn = proto.Config.PG_DSN
|
||||
db, err = gorm.Open(postgres.Open(dsn), &gorm.Config{})
|
||||
} else if proto.Config.DB == 2 { //sqlite
|
||||
dsn = proto.Config.SQLITE_FILE
|
||||
db, err = gorm.Open(sqlite.Open(dsn), &gorm.Config{})
|
||||
}
|
||||
|
||||
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
|
||||
if err != nil {
|
||||
panic("failed to connect database")
|
||||
return err
|
||||
}
|
||||
err = db.AutoMigrate(&User{})
|
||||
if err != nil {
|
||||
fmt.Println("user table:", err)
|
||||
return err
|
||||
} // 自动迁移,创建表,如果表已经存在,会自动更新表结构,不会删除表,只会创建不存在的表
|
||||
//err = db.AutoMigrate(&User{})
|
||||
//if err != nil {
|
||||
// fmt.Println("user table:", err)
|
||||
// return err
|
||||
//}
|
||||
err = db.AutoMigrate(&Video{})
|
||||
if err != nil {
|
||||
fmt.Println("video table:", err)
|
||||
|
|
@ -67,11 +85,43 @@ func Init() error {
|
|||
return err
|
||||
}
|
||||
|
||||
err = db.AutoMigrate(&File{})
|
||||
if err != nil {
|
||||
fmt.Println("file table:", err)
|
||||
return err
|
||||
}
|
||||
|
||||
err = db.AutoMigrate(&ConfigFile{})
|
||||
if err != nil {
|
||||
fmt.Println("config file table:", err)
|
||||
return err
|
||||
}
|
||||
|
||||
err = db.AutoMigrate(&FileAuth{})
|
||||
if err != nil {
|
||||
fmt.Println("file auth table:", err)
|
||||
return err
|
||||
}
|
||||
|
||||
err = db.AutoMigrate(&Friend{})
|
||||
if err != nil {
|
||||
fmt.Println("friend table:", err)
|
||||
}
|
||||
|
||||
err = db.AutoMigrate(&Shell{})
|
||||
if err != nil {
|
||||
fmt.Println("shell table:", err)
|
||||
}
|
||||
|
||||
err = db.AutoMigrate(&proto.DBManage{})
|
||||
if err != nil {
|
||||
log.Println("dbmanage table:", err)
|
||||
}
|
||||
err = db.AutoMigrate(&proto.SQLRunHistory{})
|
||||
if err != nil {
|
||||
log.Println("sqlrunhistory table:", err)
|
||||
}
|
||||
|
||||
DB = db
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,261 @@
|
|||
package dao
|
||||
|
||||
import (
|
||||
"gorm.io/gorm"
|
||||
"videoplayer/proto"
|
||||
)
|
||||
|
||||
func CreateDBManage(db_info proto.DBManage) (uint, error) {
|
||||
var db2 *gorm.DB
|
||||
if proto.Config.SERVER_SQL_LOG {
|
||||
db2 = DB.Debug()
|
||||
} else {
|
||||
db2 = DB
|
||||
}
|
||||
res := db2.Create(&db_info)
|
||||
if res.Error != nil {
|
||||
return 0, res.Error
|
||||
}
|
||||
return db_info.ID, nil
|
||||
}
|
||||
|
||||
func CreateDBRunHistory(history *proto.SQLRunHistory) (uint, error) {
|
||||
var db2 *gorm.DB
|
||||
if proto.Config.SERVER_SQL_LOG {
|
||||
db2 = DB.Debug()
|
||||
} else {
|
||||
db2 = DB
|
||||
}
|
||||
res := db2.Create(history)
|
||||
if res.Error != nil {
|
||||
return 0, res.Error
|
||||
}
|
||||
return history.ID, nil
|
||||
}
|
||||
|
||||
func RunSQL(sql string, db_ *gorm.DB) (res []map[string]interface{}, err error) {
|
||||
var db2 *gorm.DB
|
||||
if proto.Config.SERVER_SQL_LOG {
|
||||
db2 = db_.Debug()
|
||||
} else {
|
||||
db2 = db_
|
||||
}
|
||||
err = db2.Raw(sql).Scan(&res).Error
|
||||
return res, err
|
||||
}
|
||||
|
||||
func FindDBManageByID(id uint) (proto.DBManage, error) {
|
||||
var db_info proto.DBManage
|
||||
var db2 *gorm.DB
|
||||
if proto.Config.SERVER_SQL_LOG {
|
||||
db2 = DB.Debug()
|
||||
} else {
|
||||
db2 = DB
|
||||
}
|
||||
res := db2.Where("id = ?", id).First(&db_info)
|
||||
if res.Error != nil {
|
||||
return proto.DBManage{}, res.Error
|
||||
}
|
||||
return db_info, nil
|
||||
}
|
||||
|
||||
func FindDBManageByAuthID(auth_id uint) ([]proto.DBManage, error) {
|
||||
var db_infos []proto.DBManage
|
||||
var db2 *gorm.DB
|
||||
if proto.Config.SERVER_SQL_LOG {
|
||||
db2 = DB.Debug()
|
||||
} else {
|
||||
db2 = DB
|
||||
}
|
||||
res := db2.Where("user_id = ?", auth_id).Find(&db_infos)
|
||||
if res.Error != nil {
|
||||
return nil, res.Error
|
||||
}
|
||||
return db_infos, nil
|
||||
}
|
||||
|
||||
func FindAllDBManage() ([]proto.DBManage, error) {
|
||||
var db_infos []proto.DBManage
|
||||
var db2 *gorm.DB
|
||||
if proto.Config.SERVER_SQL_LOG {
|
||||
db2 = DB.Debug()
|
||||
} else {
|
||||
db2 = DB
|
||||
}
|
||||
res := db2.Find(&db_infos)
|
||||
if res.Error != nil {
|
||||
return nil, res.Error
|
||||
}
|
||||
return db_infos, nil
|
||||
}
|
||||
|
||||
func UpdateDBManage(id uint, db_info *proto.DBManage) error {
|
||||
var db2 *gorm.DB
|
||||
if proto.Config.SERVER_SQL_LOG {
|
||||
db2 = DB.Debug()
|
||||
} else {
|
||||
db2 = DB
|
||||
}
|
||||
res := db2.Model(&proto.DBManage{}).Where("id = ?", id).Updates(db_info)
|
||||
return res.Error
|
||||
}
|
||||
|
||||
func DeleteDBManageByID(id uint) error {
|
||||
var db2 *gorm.DB
|
||||
if proto.Config.SERVER_SQL_LOG {
|
||||
db2 = DB.Debug()
|
||||
} else {
|
||||
db2 = DB
|
||||
}
|
||||
res := db2.Where("id = ?", id).Delete(&proto.DBManage{})
|
||||
return res.Error
|
||||
}
|
||||
|
||||
func DeleteDBManageByUserID(id uint) error {
|
||||
var db2 *gorm.DB
|
||||
if proto.Config.SERVER_SQL_LOG {
|
||||
db2 = DB.Debug()
|
||||
} else {
|
||||
db2 = DB
|
||||
}
|
||||
res := db2.Where("user_id = ?", id).Delete(&proto.DBManage{})
|
||||
return res.Error
|
||||
}
|
||||
|
||||
func FindDBRunHistoryByID(id uint) (proto.SQLRunHistory, error) {
|
||||
var history proto.SQLRunHistory
|
||||
var db2 *gorm.DB
|
||||
if proto.Config.SERVER_SQL_LOG {
|
||||
db2 = DB.Debug()
|
||||
} else {
|
||||
db2 = DB
|
||||
}
|
||||
res := db2.Where("id = ?", id).First(&history)
|
||||
if res.Error != nil {
|
||||
return proto.SQLRunHistory{}, res.Error
|
||||
}
|
||||
return history, nil
|
||||
}
|
||||
func FindDBRunHistoryByAuthID(auth_id int) ([]proto.SQLRunHistory, error) {
|
||||
var histories []proto.SQLRunHistory
|
||||
var db2 *gorm.DB
|
||||
if proto.Config.SERVER_SQL_LOG {
|
||||
db2 = DB.Debug()
|
||||
} else {
|
||||
db2 = DB
|
||||
}
|
||||
res := db2.Where("user_id = ?", auth_id).Find(&histories)
|
||||
if res.Error != nil {
|
||||
return nil, res.Error
|
||||
}
|
||||
return histories, nil
|
||||
}
|
||||
|
||||
func FindDBRunHistoryByAuthIDAndDbId(auth_id int, db_id uint) ([]proto.SQLRunHistory, error) {
|
||||
var histories []proto.SQLRunHistory
|
||||
var db2 *gorm.DB
|
||||
if proto.Config.SERVER_SQL_LOG {
|
||||
db2 = DB.Debug()
|
||||
} else {
|
||||
db2 = DB
|
||||
}
|
||||
res := db2.Where("user_id = ? and db_id = ?", auth_id, db_id).Find(&histories)
|
||||
if res.Error != nil {
|
||||
return nil, res.Error
|
||||
}
|
||||
return histories, nil
|
||||
}
|
||||
|
||||
func DelSQLRunHistoryByID(id uint) error {
|
||||
var db2 *gorm.DB
|
||||
if proto.Config.SERVER_SQL_LOG {
|
||||
db2 = DB.Debug()
|
||||
} else {
|
||||
db2 = DB
|
||||
}
|
||||
res := db2.Where("id = ?", id).Delete(&proto.SQLRunHistory{})
|
||||
return res.Error
|
||||
}
|
||||
|
||||
func DelSQLRunHistoryByAuthID(auth_id int) error {
|
||||
var db2 *gorm.DB
|
||||
if proto.Config.SERVER_SQL_LOG {
|
||||
db2 = DB.Debug()
|
||||
} else {
|
||||
db2 = DB
|
||||
}
|
||||
res := db2.Where("user_id = ?", auth_id).Delete(&proto.SQLRunHistory{})
|
||||
return res.Error
|
||||
}
|
||||
|
||||
func FindAllSQLRunHistory() ([]proto.SQLRunHistory, error) {
|
||||
var histories []proto.SQLRunHistory
|
||||
var db2 *gorm.DB
|
||||
if proto.Config.SERVER_SQL_LOG {
|
||||
db2 = DB.Debug()
|
||||
} else {
|
||||
db2 = DB
|
||||
}
|
||||
res := db2.Find(&histories)
|
||||
if res.Error != nil {
|
||||
return nil, res.Error
|
||||
}
|
||||
return histories, nil
|
||||
}
|
||||
|
||||
func RunSQLWithOrder(sql string, db_ *gorm.DB) (result proto.SQLResult, err error) {
|
||||
var db2 *gorm.DB
|
||||
// 保留 Debug 模式
|
||||
if proto.Config.SERVER_SQL_LOG {
|
||||
db2 = db_.Debug()
|
||||
} else {
|
||||
db2 = db_
|
||||
}
|
||||
|
||||
// 执行 SQL 并获取底层 Rows 对象
|
||||
rows, err := db2.Raw(sql).Rows()
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
defer rows.Close() // 确保关闭 Rows
|
||||
|
||||
// 获取列名顺序(关键:这里的顺序与 SQL 查询的列顺序一致)
|
||||
columns, err := rows.Columns()
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
for _, col := range columns {
|
||||
result.Columns = append(result.Columns, proto.SQLResultColumnsValue{Prop: col, Label: col})
|
||||
}
|
||||
|
||||
// 遍历每行数据
|
||||
for rows.Next() {
|
||||
// 准备接收每行数据的容器(按列顺序)
|
||||
values := make([]interface{}, len(columns))
|
||||
valuePtrs := make([]interface{}, len(columns)) // 用于 Scan 的指针切片
|
||||
|
||||
// 为每个列绑定指针(Scan 要求传入指针)
|
||||
for i := range values {
|
||||
valuePtrs[i] = &values[i]
|
||||
}
|
||||
|
||||
// 扫描当前行数据到指针切片
|
||||
if err2 := rows.Scan(valuePtrs...); err2 != nil {
|
||||
return result, err2
|
||||
}
|
||||
|
||||
// 将当前行数据存入 map(便于按列名访问)
|
||||
rowMap := make(map[string]interface{})
|
||||
for i, col := range columns {
|
||||
rowMap[col] = values[i]
|
||||
}
|
||||
result.Rows = append(result.Rows, rowMap)
|
||||
}
|
||||
|
||||
// 检查遍历过程中是否有错误
|
||||
if err = rows.Err(); err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
|
@ -18,7 +18,7 @@ type Device struct {
|
|||
|
||||
func CreateDevice(authID int, deviceName, deviceType string, deviceStatus, deviceLocation, deviceIP, deviceInfo string) uint {
|
||||
device := Device{AuthID: authID, DeviceName: deviceName, DeviceType: deviceType, DeviceStatus: deviceStatus, DeviceLocation: deviceLocation, DeviceIP: deviceIP, DeviceInfo: deviceInfo}
|
||||
result := DB.Debug().Create(&device)
|
||||
result := DB.Create(&device)
|
||||
if result.Error != nil {
|
||||
fmt.Println("CreateDevice failed", result.Error)
|
||||
return 0
|
||||
|
|
@ -27,7 +27,7 @@ func CreateDevice(authID int, deviceName, deviceType string, deviceStatus, devic
|
|||
}
|
||||
|
||||
func DeleteDeviceByID(id, user int) bool {
|
||||
res := DB.Debug().Model(&Device{}).Where("id = ? and auth_id = ?", id, user).Delete(&Device{})
|
||||
res := DB.Model(&Device{}).Where("id = ? and auth_id = ?", id, user).Delete(&Device{})
|
||||
if res.Error != nil {
|
||||
return false
|
||||
}
|
||||
|
|
@ -36,18 +36,18 @@ func DeleteDeviceByID(id, user int) bool {
|
|||
|
||||
func FindDeviceByID(id, auth_id int) Device {
|
||||
var device Device
|
||||
DB.Debug().Where("id = ? and auth_id = ?", id, auth_id).First(&device)
|
||||
DB.Where("id = ? and auth_id = ?", id, auth_id).First(&device)
|
||||
return device
|
||||
}
|
||||
|
||||
func FindDeviceByAuthID(auth_id int) []Device {
|
||||
var devices []Device
|
||||
DB.Debug().Where("auth_id = ?", auth_id).Find(&devices)
|
||||
DB.Where("auth_id = ?", auth_id).Find(&devices)
|
||||
return devices
|
||||
}
|
||||
|
||||
func SetDeviceStatus(status string, id, auth_id int) bool {
|
||||
result := DB.Debug().Model(&Device{}).Where("id = ? and auth_id = ?", id, auth_id).Updates(Device{DeviceStatus: status})
|
||||
result := DB.Model(&Device{}).Where("id = ? and auth_id = ?", id, auth_id).Updates(Device{DeviceStatus: status})
|
||||
if result.Error != nil {
|
||||
return false
|
||||
}
|
||||
|
|
@ -78,7 +78,7 @@ func UpdateDeviceByID(id, auth_id int, deviceName, deviceType, deviceStatus, dev
|
|||
deviceInfo = pd.DeviceInfo
|
||||
}
|
||||
}
|
||||
res := DB.Debug().Model(&Device{}).Where("id = ? and auth_id = ?", id, auth_id).Updates(Device{DeviceName: deviceName, DeviceType: deviceType, DeviceStatus: deviceStatus, DeviceLocation: deviceLocation, DeviceIP: deviceIP, DeviceInfo: deviceInfo})
|
||||
res := DB.Model(&Device{}).Where("id = ? and auth_id = ?", id, auth_id).Updates(Device{DeviceName: deviceName, DeviceType: deviceType, DeviceStatus: deviceStatus, DeviceLocation: deviceLocation, DeviceIP: deviceIP, DeviceInfo: deviceInfo})
|
||||
if res.Error != nil {
|
||||
return false
|
||||
}
|
||||
|
|
|
|||
130
dao/file.go
130
dao/file.go
|
|
@ -1,29 +1,51 @@
|
|||
package dao
|
||||
|
||||
import "gorm.io/gorm"
|
||||
import (
|
||||
"gorm.io/gorm"
|
||||
"videoplayer/proto"
|
||||
)
|
||||
|
||||
type File struct {
|
||||
gorm.Model
|
||||
// 存储文件名
|
||||
FileStoreName string `gorm:"column:file_store_name;uniqueIndex:idx_file_name"`
|
||||
FileStoreName string `gorm:"column:file_store_name;type:varchar(255);uniqueIndex:idx_file_name"`
|
||||
NeedAuth bool `gorm:"column:need_auth"`
|
||||
FileName string `gorm:"column:file_name"`
|
||||
FileSize int `gorm:"column:file_size"`
|
||||
FileType string `gorm:"column:file_type"`
|
||||
FilePath string `gorm:"column:file_path"`
|
||||
AuthID int `gorm:"column:auth_id"`
|
||||
Md5 string `gorm:"column:md5;type:varchar(255);uniqueIndex:idx_file_name"`
|
||||
}
|
||||
|
||||
func CreateFile(fileStoreName, fileName, fileType, filePath string, fileSize, authID int) uint {
|
||||
file := File{FileStoreName: fileStoreName, FileName: fileName, FileType: fileType, FilePath: filePath, FileSize: fileSize, AuthID: authID}
|
||||
result := DB.Debug().Create(&file)
|
||||
type FileAuth struct {
|
||||
gorm.Model
|
||||
AuthID int `gorm:"column:auth_id"`
|
||||
FileID int `gorm:"column:file_id"`
|
||||
UserFileName string `gorm:"column:user_file_name;type:varchar(255);uniqueIndex:idx_file_name"` //对于同一个文件,不同用户有不同的文件名
|
||||
UploadType string `gorm:"column:upload_type"` // 上传类型: im,avatar,file,config,config为系统文件
|
||||
IsPrivate int `gorm:"column:is_private"` // 是否私有,私有文件只能自己下载或者通过分享链接下载,1为私有,0为公开
|
||||
ShareCode string `gorm:"column:share_code"` // 分享码,用于分享时的验证,构建分享链接
|
||||
}
|
||||
|
||||
type ConfigFile struct {
|
||||
gorm.Model
|
||||
AuthID int `gorm:"column:auth_id"`
|
||||
FileName string `gorm:"column:file_name"`
|
||||
FilePath string `gorm:"column:file_path"`
|
||||
}
|
||||
|
||||
func CreateFile(fileStoreName, fileName, fileType, filePath, md5Str string, fileSize, authID int, NeedAuth bool) File {
|
||||
file := File{FileStoreName: fileStoreName, FileName: fileName, FileType: fileType, FilePath: filePath, FileSize: fileSize, AuthID: authID, NeedAuth: NeedAuth, Md5: md5Str}
|
||||
result := DB.Create(&file)
|
||||
if result.Error != nil {
|
||||
return 0
|
||||
return File{}
|
||||
}
|
||||
return file.ID
|
||||
return file
|
||||
}
|
||||
|
||||
func DeleteFileByID(id, user int) bool {
|
||||
res := DB.Debug().Model(&File{}).Where("id = ? and auth_id = ?", id, user).Delete(&File{})
|
||||
res := DB.Model(&File{}).Where("id = ? and auth_id = ?", id, user).Delete(&File{})
|
||||
if res.Error != nil {
|
||||
return false
|
||||
}
|
||||
|
|
@ -32,19 +54,25 @@ func DeleteFileByID(id, user int) bool {
|
|||
|
||||
func FindFileByID(id, auth_id int) File {
|
||||
var file File
|
||||
DB.Debug().Where("id = ? and auth_id = ?", id, auth_id).First(&file)
|
||||
DB.Where("id = ? and auth_id = ?", id, auth_id).First(&file)
|
||||
return file
|
||||
}
|
||||
|
||||
func FindFileByNames(fileName string, auth_id int) File {
|
||||
var file File
|
||||
DB.Debug().Where("file_name = ? and auth_id = ?", fileName, auth_id).First(&file)
|
||||
DB.Where("file_name = ? and auth_id = ?", fileName, auth_id).First(&file)
|
||||
return file
|
||||
}
|
||||
|
||||
func FindFileByName(fileName string) File {
|
||||
var file File
|
||||
DB.Where("file_store_name = ?", fileName).First(&file)
|
||||
return file
|
||||
}
|
||||
|
||||
func FindFileByAuthID(auth_id int) []File {
|
||||
var files []File
|
||||
DB.Debug().Where("auth_id = ?", auth_id).Find(&files)
|
||||
DB.Where("auth_id = ?", auth_id).Find(&files)
|
||||
return files
|
||||
}
|
||||
|
||||
|
|
@ -53,7 +81,7 @@ func UpdateFileByID(id, auth_id int, fileStoreName, fileName, fileType, filePath
|
|||
if pd.ID == 0 {
|
||||
return false
|
||||
}
|
||||
result := DB.Debug().Model(&File{}).Where("id = ? and auth_id = ?", id, auth_id).Updates(File{FileStoreName: fileStoreName, FileName: fileName, FileType: fileType, FilePath: filePath, FileSize: fileSize})
|
||||
result := DB.Model(&File{}).Where("id = ? and auth_id = ?", id, auth_id).Updates(File{FileStoreName: fileStoreName, FileName: fileName, FileType: fileType, FilePath: filePath, FileSize: fileSize})
|
||||
if result.Error != nil {
|
||||
return false
|
||||
}
|
||||
|
|
@ -61,7 +89,7 @@ func UpdateFileByID(id, auth_id int, fileStoreName, fileName, fileType, filePath
|
|||
}
|
||||
|
||||
func DeleteFileByAuthID(auth_id int) bool {
|
||||
res := DB.Debug().Model(&File{}).Where("auth_id = ?", auth_id).Delete(&File{})
|
||||
res := DB.Model(&File{}).Where("auth_id = ?", auth_id).Delete(&File{})
|
||||
if res.Error != nil {
|
||||
return false
|
||||
}
|
||||
|
|
@ -69,9 +97,83 @@ func DeleteFileByAuthID(auth_id int) bool {
|
|||
}
|
||||
|
||||
func DeleteFileById(id int) bool {
|
||||
res := DB.Debug().Model(&File{}).Where("id = ?", id).Delete(&File{})
|
||||
res := DB.Model(&File{}).Where("id = ?", id).Delete(&File{})
|
||||
if res.Error != nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func FindFileByMd5(md5 string) File {
|
||||
var file File
|
||||
if proto.Config.SERVER_SQL_LOG {
|
||||
DB.Debug().Where("md5 = ?", md5).First(&file)
|
||||
} else {
|
||||
DB.Where("md5 = ?", md5).First(&file)
|
||||
}
|
||||
return file
|
||||
}
|
||||
|
||||
func CreateFileAuth(authID, fileID int, userFileName, uploadType string, isPrivate int, shareCode string) FileAuth {
|
||||
fileAuth := FileAuth{AuthID: authID, FileID: fileID, UserFileName: userFileName, UploadType: uploadType, IsPrivate: isPrivate, ShareCode: shareCode}
|
||||
var result *gorm.DB
|
||||
if proto.Config.SERVER_SQL_LOG {
|
||||
result = DB.Debug().Create(&fileAuth)
|
||||
} else {
|
||||
result = DB.Create(&fileAuth)
|
||||
}
|
||||
if result.Error != nil {
|
||||
return FileAuth{}
|
||||
}
|
||||
return fileAuth
|
||||
}
|
||||
|
||||
func CreateConfigFile(file ConfigFile) (id uint, err error) {
|
||||
var result *gorm.DB
|
||||
if proto.Config.SERVER_SQL_LOG {
|
||||
result = DB.Debug().Create(&file)
|
||||
} else {
|
||||
result = DB.Create(&file)
|
||||
}
|
||||
return file.ID, result.Error
|
||||
}
|
||||
|
||||
func FindConfigFileByID(id int, user_id int) ConfigFile {
|
||||
var file ConfigFile
|
||||
if proto.Config.SERVER_SQL_LOG {
|
||||
DB.Debug().Where("id = ? and auth_id = ?", id, user_id).First(&file)
|
||||
} else {
|
||||
DB.Where("id = ? and auth_id = ?", id, user_id).First(&file)
|
||||
}
|
||||
return file
|
||||
}
|
||||
|
||||
func DeleteConfigFileByID(id int) error {
|
||||
var res *gorm.DB
|
||||
if proto.Config.SERVER_SQL_LOG {
|
||||
res = DB.Debug().Delete(&ConfigFile{}, id)
|
||||
} else {
|
||||
res = DB.Delete(&ConfigFile{}, id)
|
||||
}
|
||||
return res.Error
|
||||
}
|
||||
|
||||
func UpdateConfigFileByID(id int, file ConfigFile) error {
|
||||
var res *gorm.DB
|
||||
if proto.Config.SERVER_SQL_LOG {
|
||||
res = DB.Debug().Model(&ConfigFile{}).Where("id = ?", id).Updates(&file)
|
||||
} else {
|
||||
res = DB.Model(&ConfigFile{}).Where("id = ?", id).Updates(&file)
|
||||
}
|
||||
return res.Error
|
||||
}
|
||||
|
||||
func FindConfigFileByAuthID(auth_id int) []ConfigFile {
|
||||
var files []ConfigFile
|
||||
if proto.Config.SERVER_SQL_LOG {
|
||||
DB.Debug().Where("auth_id = ?", auth_id).Find(&files)
|
||||
} else {
|
||||
DB.Where("auth_id = ?", auth_id).Find(&files)
|
||||
}
|
||||
return files
|
||||
}
|
||||
|
|
|
|||
85
dao/im.go
85
dao/im.go
|
|
@ -40,13 +40,13 @@ type Friend struct {
|
|||
// 创建单聊消息
|
||||
func CreateSimpleMessage(from_user_id, to_user_id int, message string) (error, uint) {
|
||||
msg := Message{FromUserID: from_user_id, ToUserID: to_user_id, Msg: message, Type: proto.MSG_TYPE_SIMPLE, Status: proto.MSG_STATUS_UNREAD}
|
||||
res := DB.Debug().Create(&msg)
|
||||
res := DB.Create(&msg)
|
||||
return res.Error, msg.ID
|
||||
}
|
||||
|
||||
func CreateGeneralMessage(from_user_id, to_user_id, msg_type, status, group_id int, message string) (error error, id uint) {
|
||||
msg := Message{FromUserID: from_user_id, ToUserID: to_user_id, Msg: message, Type: msg_type, Status: status, GroupID: group_id}
|
||||
res := DB.Debug().Create(&msg)
|
||||
res := DB.Create(&msg)
|
||||
return res.Error, msg.ID
|
||||
}
|
||||
|
||||
|
|
@ -55,13 +55,13 @@ func GetMsgUserByIndex(from_user_id, to_user_id, msg_type, index, status int) ([
|
|||
var msgs []Message
|
||||
var res *gorm.DB
|
||||
if msg_type == 4 {
|
||||
res = DB.Debug().Where("from_user_id = ? and to_user_id = ? and type = ? and status = ? ", from_user_id, to_user_id, msg_type, status).Order("created_at DESC").Limit(20 * index).Find(&msgs)
|
||||
res = DB.Where("from_user_id = ? and to_user_id = ? and type = ? and status = ? ", from_user_id, to_user_id, msg_type, status).Order("created_at DESC").Limit(20 * index).Find(&msgs)
|
||||
} else if msg_type == 1 {
|
||||
//单聊,只有两个人的消息
|
||||
res = DB.Debug().Raw("select * from messages where (from_user_id = ? AND to_user_id = ?) and type = ? or (from_user_id = ? AND to_user_id = ?) and type = ? order by created_at desc limit ?", from_user_id, to_user_id, msg_type, to_user_id, from_user_id, msg_type, 20*index).Scan(&msgs)
|
||||
//res = DB.Debug().Where("(from_user_id = ? AND to_user_id = ?) or (from_user_id = ? AND to_user_id = ?) and type = ? ", from_user_id, to_user_id, to_user_id, from_user_id, msg_type).Order("created_at DESC").Limit(20 * index).Find(&msgs)
|
||||
res = DB.Raw("select * from messages where (from_user_id = ? AND to_user_id = ?) and type = ? or (from_user_id = ? AND to_user_id = ?) and type = ? order by created_at desc limit ?", from_user_id, to_user_id, msg_type, to_user_id, from_user_id, msg_type, 20*index).Scan(&msgs)
|
||||
//res = DB.Where("(from_user_id = ? AND to_user_id = ?) or (from_user_id = ? AND to_user_id = ?) and type = ? ", from_user_id, to_user_id, to_user_id, from_user_id, msg_type).Order("created_at DESC").Limit(20 * index).Find(&msgs)
|
||||
} else {
|
||||
res = DB.Debug().Where("from_user_id = ? and to_user_id = ? and type = ? ", from_user_id, to_user_id, msg_type).Order("created_at DESC").Limit(20 * index).Find(&msgs)
|
||||
res = DB.Where("from_user_id = ? and to_user_id = ? and type = ? ", from_user_id, to_user_id, msg_type).Order("created_at DESC").Limit(20 * index).Find(&msgs)
|
||||
}
|
||||
return msgs, res.Error
|
||||
}
|
||||
|
|
@ -73,27 +73,27 @@ type GroupMessage struct {
|
|||
|
||||
func GetMsgGroupByIndex(group_id, index int) ([]GroupMessage, error) {
|
||||
var msgs []GroupMessage
|
||||
res := DB.Debug().Raw("select messages.*,users.name from messages join users on messages.from_user_id = users.id where type = 2 and group_id = ? order by created_at desc limit ?", group_id, 20*index).Scan(&msgs)
|
||||
res := DB.Raw("select messages.*,users.name from messages join users on messages.from_user_id = users.id where type = 2 and group_id = ? order by created_at desc limit ?", group_id, 20*index).Scan(&msgs)
|
||||
return msgs, res.Error
|
||||
|
||||
}
|
||||
|
||||
func GetGroupRequestUsers(user_id int) []FriendRequest {
|
||||
var users []FriendRequest
|
||||
DB.Debug().Raw("select id,im_id,name,email FROM (SELECT im_id,from_user_id,group_id FROM (( SELECT id as im_id,from_user_id,group_id FROM messages WHERE type=? and status=? ) as m JOIN groups as g on g.id=m.group_id ) where g.auth_id=? ) as e JOIN users as u ON e.from_user_id=u.id", proto.MSG_TYPE_GROUP_INVI, 0, user_id).Scan(&users)
|
||||
func GetGroupRequestUsers(user_id int) []GroupRequestUsers {
|
||||
var users []GroupRequestUsers
|
||||
DB.Raw("select id,im_id,name,email,group_id FROM (SELECT im_id,from_user_id,group_id FROM (( SELECT id as im_id,from_user_id,group_id FROM messages WHERE type=? and status=? ) as m JOIN groups as g on g.id=m.group_id ) where g.auth_id=? ) as e JOIN users as u ON e.from_user_id=u.id", proto.MSG_TYPE_GROUP_ADD, 0, user_id).Scan(&users)
|
||||
return users
|
||||
}
|
||||
|
||||
func GetMsgUserGroupReq(from_user_id, group_id int) ([]Message, error) {
|
||||
var msgs []Message
|
||||
res := DB.Debug().Where("from_user_id = ? and group_id = ? and type = ? and status = ?", from_user_id, group_id, 5, 0).Find(&msgs)
|
||||
res := DB.Where("from_user_id = ? and group_id = ? and type = ? and status = ?", from_user_id, group_id, 5, 0).Find(&msgs)
|
||||
return msgs, res.Error
|
||||
}
|
||||
|
||||
// 获取邀请消息
|
||||
func GetFriendGroupReq(user_id int) ([]Message, error) {
|
||||
var msgs []Message
|
||||
res := DB.Debug().Where("to_user_id = ? and type = ?", user_id, proto.MSG_TYPE_FRIEND).Find(&msgs)
|
||||
res := DB.Where("to_user_id = ? and type = ?", user_id, proto.MSG_TYPE_FRIEND).Find(&msgs)
|
||||
return msgs, res.Error
|
||||
}
|
||||
|
||||
|
|
@ -146,21 +146,21 @@ func DeleteFriend(user_id, friend_id int) error {
|
|||
// 通过id查找消息
|
||||
func FindMessageByID(id uint) []Message {
|
||||
var msgs []Message
|
||||
DB.Debug().Where("id = ?", id).Find(&msgs)
|
||||
DB.Where("id = ?", id).Find(&msgs)
|
||||
return msgs
|
||||
}
|
||||
|
||||
// 通过id查找消息(包括name)
|
||||
func FindMessageByID2(id uint) []GroupMessage {
|
||||
var msgs []GroupMessage
|
||||
DB.Debug().Raw("select messages.*,users.name from messages join users on messages.from_user_id = users.id where messages.id = ?", id).Scan(&msgs)
|
||||
DB.Raw("select messages.*,users.name from messages join users on messages.from_user_id = users.id where messages.id = ?", id).Scan(&msgs)
|
||||
return msgs
|
||||
|
||||
}
|
||||
|
||||
// 更新消息状态
|
||||
func UpdateMessageStatus(id uint, status int) error {
|
||||
res := DB.Debug().Model(&Message{}).Where("id = ?", id).Update("status", status)
|
||||
res := DB.Model(&Message{}).Where("id = ?", id).Update("status", status)
|
||||
return res.Error
|
||||
}
|
||||
|
||||
|
|
@ -188,79 +188,86 @@ func CreateGroup(groupName, groupInfo, groupType, groupIcon string, user_id int)
|
|||
// 查找用户是否在群聊
|
||||
func FindGroupUser(user_id, group_id int) []GroupUser {
|
||||
var groupUsers []GroupUser
|
||||
DB.Debug().Where("user_id = ? and group_id = ?", user_id, group_id).Find(&groupUsers)
|
||||
DB.Where("user_id = ? and group_id = ?", user_id, group_id).Find(&groupUsers)
|
||||
return groupUsers
|
||||
}
|
||||
|
||||
// 加入群聊
|
||||
func JoinGroup(group_id, user_id int) (error, uint) {
|
||||
groupUser := GroupUser{GroupID: group_id, UserID: user_id}
|
||||
res := DB.Debug().Create(&groupUser)
|
||||
res := DB.Create(&groupUser)
|
||||
return res.Error, groupUser.ID
|
||||
}
|
||||
|
||||
// 退出群聊
|
||||
func QuitGroup(group_id, user_id int) error {
|
||||
res := DB.Debug().Delete(&GroupUser{}, "group_id = ? and user_id = ?", group_id, user_id)
|
||||
res := DB.Delete(&GroupUser{}, "group_id = ? and user_id = ?", group_id, user_id)
|
||||
return res.Error
|
||||
}
|
||||
|
||||
// 根据群id查找群
|
||||
func FindGroup(group_id int) []Group {
|
||||
var groups []Group
|
||||
DB.Debug().Where("id = ?", group_id).Find(&groups)
|
||||
DB.Where("id = ?", group_id).Find(&groups)
|
||||
return groups
|
||||
}
|
||||
|
||||
// 删除群聊
|
||||
func DeleteGroup(group_id int, auth_id int) error {
|
||||
res := DB.Debug().Delete(&Group{}, "id = ? and auth_id = ?", group_id, auth_id)
|
||||
res := DB.Delete(&Group{}, "id = ? and auth_id = ?", group_id, auth_id)
|
||||
return res.Error
|
||||
}
|
||||
|
||||
// 删除群里的用户
|
||||
func DeleteGroupUsers(group_id int) error {
|
||||
res := DB.Debug().Delete(&GroupUser{}, "group_id = ?", group_id)
|
||||
res := DB.Delete(&GroupUser{}, "group_id = ?", group_id)
|
||||
return res.Error
|
||||
}
|
||||
|
||||
func FindFriend(from_user_id, to_user_id int) []Friend {
|
||||
var friends []Friend
|
||||
DB.Debug().Where("user_id = ? and friend_id = ?", from_user_id, to_user_id).Find(&friends)
|
||||
DB.Where("user_id = ? and friend_id = ?", from_user_id, to_user_id).Find(&friends)
|
||||
return friends
|
||||
}
|
||||
|
||||
type FriendRet struct {
|
||||
ID int `json:"id"` //用户id
|
||||
Name string `json:"name"` //用户名
|
||||
Email string `json:"email"` //邮箱
|
||||
ID int `json:"id"` //用户id
|
||||
Name string `json:"name"` //用户名
|
||||
Email string `json:"email"` //邮箱
|
||||
Avatar string `json:"avatar"` //头像
|
||||
}
|
||||
|
||||
func FindFriendsIDs(user_id int) []Friend {
|
||||
var friends []Friend
|
||||
DB.Where("user_id = ?", user_id).Find(&friends)
|
||||
return friends
|
||||
}
|
||||
|
||||
func FindFriends(user_id int) []FriendRet {
|
||||
var friends []FriendRet
|
||||
DB.Debug().Raw("select users.id, users.name, users.email from users join friends on users.id = friends.friend_id where friends.user_id = ? and friends.deleted_at is null", user_id).Scan(&friends)
|
||||
DB.Raw("select distinct users.id, users.name, users.email,users.avatar from users join friends on users.id = friends.friend_id where friends.user_id = ? and friends.deleted_at is null", user_id).Scan(&friends)
|
||||
return friends
|
||||
}
|
||||
func GetGroups(user_id int) []Group {
|
||||
var groups []Group
|
||||
DB.Debug().Where("auth_id = ?", user_id).Find(&groups)
|
||||
DB.Where("auth_id = ?", user_id).Find(&groups)
|
||||
return groups
|
||||
}
|
||||
|
||||
func FindGroups(user_id int) []Group {
|
||||
var groups []Group
|
||||
DB.Debug().Raw("select groups.* from groups join group_users on groups.id = group_users.group_id where group_users.user_id = ? and group_users.deleted_at is null", user_id).Scan(&groups)
|
||||
DB.Raw("select groups.* from groups join group_users on groups.id = group_users.group_id where group_users.user_id = ? and group_users.deleted_at is null", user_id).Scan(&groups)
|
||||
return groups
|
||||
}
|
||||
|
||||
func FindGroupByID(group_id int) []Group {
|
||||
var groups []Group
|
||||
DB.Debug().Where("id = ?", group_id).Find(&groups)
|
||||
DB.Where("id = ?", group_id).Find(&groups)
|
||||
return groups
|
||||
}
|
||||
|
||||
func UpdateGroup(group_id int, groupName, groupInfo, groupIcon string) error {
|
||||
res := DB.Debug().Model(&Group{}).Where("id = ?", group_id).Updates(map[string]interface{}{"group_name": groupName, "group_info": groupInfo, "group_icon": groupIcon})
|
||||
func UpdateGroup(group_id int, groupName, groupInfo, groupType, groupIcon string, user_id int) error {
|
||||
res := DB.Model(&Group{}).Where("id = ? and auth_id = ? ", group_id, user_id).Updates(map[string]interface{}{"group_name": groupName, "group_info": groupInfo, "group_icon": groupIcon, "group_type": groupType})
|
||||
return res.Error
|
||||
}
|
||||
|
||||
|
|
@ -272,20 +279,30 @@ type FriendRequest struct {
|
|||
Age int `json:"age"`
|
||||
}
|
||||
|
||||
type GroupRequestUsers struct {
|
||||
FriendRequest
|
||||
GroupID int `json:"group_id"`
|
||||
}
|
||||
|
||||
func GetFriendRequest(user_id int) []FriendRequest {
|
||||
var users []FriendRequest
|
||||
DB.Debug().Raw("select users.id,users.name,users.email,users.age,messages.id as im_id from users join messages on users.id = messages.from_user_id where messages.to_user_id = ? and messages.type = ? and status = ?", user_id, proto.MSG_TYPE_FRIEND, 0).Scan(&users)
|
||||
DB.Raw("select users.id,users.name,users.email,users.age,messages.id as im_id from users join messages on users.id = messages.from_user_id where messages.to_user_id = ? and messages.type = ? and status = ?", user_id, proto.MSG_TYPE_FRIEND, 0).Scan(&users)
|
||||
return users
|
||||
}
|
||||
|
||||
func FindGroupUsers(group_id int) []GroupUser {
|
||||
var groupUsers []GroupUser
|
||||
DB.Debug().Where("group_id = ?", group_id).Find(&groupUsers)
|
||||
DB.Where("group_id = ?", group_id).Find(&groupUsers)
|
||||
return groupUsers
|
||||
}
|
||||
func FindGroupUsersInfo(group_id int) []FriendRet {
|
||||
var groupUsers []FriendRet
|
||||
DB.Raw("select distinct users.id, users.name, users.email from users join group_users on users.id = group_users.user_id where group_users.group_id = ? and group_users.deleted_at is null", group_id).Scan(&groupUsers)
|
||||
return groupUsers
|
||||
}
|
||||
|
||||
func FindGroupByNameLike(groupName string) []Group {
|
||||
var groups []Group
|
||||
DB.Debug().Where("group_name like ?", "%"+groupName+"%").Limit(20).Find(&groups)
|
||||
DB.Where("group_name like ?", "%"+groupName+"%").Limit(20).Find(&groups)
|
||||
return groups
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,3 +26,13 @@ func deleteByID(id int) bool {
|
|||
DB.Where("ID = ?", id).Delete(&Logger{})
|
||||
return true
|
||||
}
|
||||
|
||||
// 删除3天前的日志
|
||||
func DeleteLog(days int) bool {
|
||||
res := DB.Exec("delete from loggers where created_at < DATE_SUB(CURDATE(), INTERVAL ? DAY)", days)
|
||||
if res.Error != nil {
|
||||
fmt.Println("DeleteLog error", res.Error)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,133 @@
|
|||
package dao
|
||||
|
||||
import (
|
||||
"gorm.io/gorm"
|
||||
"log"
|
||||
"videoplayer/proto"
|
||||
)
|
||||
|
||||
type Shell struct {
|
||||
gorm.Model
|
||||
AuthID uint `gorm:"column:auth_id"`
|
||||
Server string `gorm:"column:server"`
|
||||
ShellName string `gorm:"column:shell_name"`
|
||||
ShellContent string `gorm:"column:shell_content"`
|
||||
Status int `gorm:"column:status"` // 0 未执行 1 执行中 2 执行完成 3 执行出错
|
||||
ShellRuntime float64 `gorm:"column:shell_runtime"` // 执行时间,单位秒
|
||||
ShellDuration float64 `gorm:"column:shell_duration"` // 执行时长,单位秒
|
||||
ShellResult string `gorm:"column:shell_result"`
|
||||
}
|
||||
|
||||
func CreateShell(shellName, shellContent, server string, uid uint) uint {
|
||||
shell := Shell{ShellName: shellName, ShellContent: shellContent, Server: server, AuthID: uid}
|
||||
var res *gorm.DB
|
||||
if proto.Config.SERVER_SQL_LOG {
|
||||
res = DB.Debug().Create(&shell)
|
||||
} else {
|
||||
res = DB.Create(&shell)
|
||||
}
|
||||
if res.Error != nil {
|
||||
return 0
|
||||
}
|
||||
return shell.ID
|
||||
}
|
||||
|
||||
func FindShellByID(id, uid uint) []Shell {
|
||||
var shell Shell
|
||||
var result *gorm.DB
|
||||
|
||||
if proto.Config.SERVER_SQL_LOG {
|
||||
result = DB.Debug().Where("id = ? and auth_id = ?", id, uid).First(&shell)
|
||||
} else {
|
||||
result = DB.Where("id = ? and auth_id = ?", id, uid).First(&shell)
|
||||
}
|
||||
var res []Shell
|
||||
res = append(res, shell)
|
||||
if result.Error != nil {
|
||||
log.Printf("FindShellByID failed: %v", result.Error)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func FindShellByAuthID(auth_id int) []Shell {
|
||||
var shells []Shell
|
||||
if proto.Config.SERVER_SQL_LOG {
|
||||
DB.Debug().Where("auth_id = ?", auth_id).Order("created_at DESC").Limit(100).Find(&shells)
|
||||
} else {
|
||||
DB.Where("auth_id = ?", auth_id).Order("created_at DESC").Limit(100).Find(&shells)
|
||||
}
|
||||
return shells
|
||||
}
|
||||
|
||||
func UpdateShellByID(id, authId uint, shellName, shellContent string, status int, shellResult string, shellRuntime, shellDuration float64) bool {
|
||||
var result *gorm.DB
|
||||
shell := Shell{ShellName: shellName, ShellContent: shellContent, Status: status, ShellResult: shellResult, ShellRuntime: shellRuntime, ShellDuration: shellDuration}
|
||||
var db2 *gorm.DB
|
||||
if proto.Config.SERVER_SQL_LOG {
|
||||
db2 = DB.Debug()
|
||||
} else {
|
||||
db2 = DB
|
||||
}
|
||||
result = db2.Model(&Shell{}).Where("id = ? and auth_id = ?", id, authId).Updates(shell)
|
||||
if result.Error != nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func FindShellWillRunByServer(server string, uid uint) []Shell {
|
||||
var shells []Shell
|
||||
if proto.Config.SERVER_SQL_LOG {
|
||||
result := DB.Debug().Where("server = ? AND auth_id = ? AND status = 0", server, uid).
|
||||
Order("created_at DESC").
|
||||
Limit(100).
|
||||
Find(&shells)
|
||||
if result.Error != nil {
|
||||
// 若查询过程中出现错误,输出错误信息
|
||||
log.Printf("Failed to query shells: %v\n", result.Error)
|
||||
}
|
||||
} else {
|
||||
//DB.Exec("select * from shells where server = ? and auth_id = ? and status = 0 order by created_at desc limit 100", server, uid).Scan(&shells)
|
||||
result := DB.Where("server = ? AND auth_id = ? AND status = 0", server, uid).
|
||||
Order("created_at DESC").
|
||||
Limit(100).
|
||||
Find(&shells)
|
||||
if result.Error != nil {
|
||||
// 若查询过程中出现错误,输出错误信息
|
||||
log.Printf("Failed to query shells: %v\n", result.Error)
|
||||
}
|
||||
}
|
||||
return shells
|
||||
}
|
||||
|
||||
func DeleteShellByID(id, authId uint) bool {
|
||||
var db2 *gorm.DB
|
||||
if proto.Config.SERVER_SQL_LOG {
|
||||
db2 = DB
|
||||
} else {
|
||||
db2 = DB.Debug()
|
||||
}
|
||||
result := db2.Where("id = ? and auth_id = ?", id, authId).Delete(&Shell{})
|
||||
|
||||
if result.Error != nil {
|
||||
log.Printf("DeleteShellByID failed: %v", result.Error)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func DeleteShellByIDV2(id uint) bool {
|
||||
var db2 *gorm.DB
|
||||
if proto.Config.SERVER_SQL_LOG {
|
||||
db2 = DB
|
||||
} else {
|
||||
db2 = DB.Debug()
|
||||
}
|
||||
result := db2.Where("id = ? ", id).Delete(&Shell{})
|
||||
|
||||
if result.Error != nil {
|
||||
log.Printf("DeleteShellByID failed: %v", result.Error)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
132
dao/user.go
132
dao/user.go
|
|
@ -8,22 +8,30 @@ import (
|
|||
|
||||
type User struct {
|
||||
gorm.Model
|
||||
Name string `gorm:"column:name"`
|
||||
Age int `gorm:"column:age"`
|
||||
Email string `gorm:"column:email"`
|
||||
Password string `gorm:"column:password"`
|
||||
Gender string `gorm:"column:gender"`
|
||||
Role string `gorm:"column:role"`
|
||||
Redis bool `gorm:"column:redis"`
|
||||
Run bool `gorm:"column:run"`
|
||||
Upload bool `gorm:"column:upload"`
|
||||
CreateTime string `gorm:"column:create_time"`
|
||||
UpdateTime string `gorm:"column:update_time"`
|
||||
Name string `gorm:"column:name"`
|
||||
Age int `gorm:"column:age"`
|
||||
Email string `gorm:"column:email"`
|
||||
Password string `gorm:"column:password"`
|
||||
Gender string `gorm:"column:gender"`
|
||||
Role string `gorm:"column:role"`
|
||||
Redis int `gorm:"column:redis"`
|
||||
Run int `gorm:"column:run"`
|
||||
Upload int `gorm:"column:upload"`
|
||||
VideoFunc int `gorm:"column:video_func"` //视频功能
|
||||
DeviceFunc int `gorm:"column:device_func"` //设备功能
|
||||
CIDFunc int `gorm:"column:cid_func"` //持续集成功能, 0为无效, -1为false, 1为true
|
||||
Avatar string `gorm:"column:avatar"`
|
||||
PasswordNeedSecondAuth int `gorm:"column:password_need_second_auth" json:"password_need_second_auth"`
|
||||
ThirdPartyNeedSecondAuth int `gorm:"column:third_party_need_second_auth" json:"third_party_need_second_auth"`
|
||||
CodeNeedSecondAuth int `gorm:"column:code_need_second_auth" json:"code_need_second_auth"`
|
||||
AISecondAuth int `json:"ai_second_auth" column:"ai_second_auth"`
|
||||
LoginAddressInfo string `gorm:"column:login_address_info" json:"login_address_info,omitempty"`
|
||||
LoginDeviceInfo string `gorm:"column:login_device_info" json:"login_device_info,omitempty"`
|
||||
}
|
||||
|
||||
func CreateUser(name, password, email, gender string, age int) uint {
|
||||
user := User{Name: name, Email: email, Password: password, Gender: gender, Age: age}
|
||||
res := DB.Debug().Create(&user)
|
||||
res := DB.Create(&user)
|
||||
if res.Error != nil {
|
||||
return 0
|
||||
}
|
||||
|
|
@ -31,47 +39,133 @@ func CreateUser(name, password, email, gender string, age int) uint {
|
|||
}
|
||||
|
||||
func DeleteUserByID(id int) int {
|
||||
DB.Delete(&User{}, id)
|
||||
res := DB.Delete(&User{}, id)
|
||||
if res.Error != nil {
|
||||
return 0
|
||||
}
|
||||
return id
|
||||
}
|
||||
|
||||
func FindUserByID(id int) []proto.User {
|
||||
var users []proto.User
|
||||
DB.Debug().Where("id = ?", id).First(&users)
|
||||
DB.Where("id = ?", id).First(&users)
|
||||
return users
|
||||
}
|
||||
func FindUserByID2(id int) User {
|
||||
var user User
|
||||
DB.Debug().Where("id = ?", id).First(&user)
|
||||
DB.Where("id = ?", id).First(&user)
|
||||
return user
|
||||
}
|
||||
|
||||
func FindUserByUserID(id int) User {
|
||||
var user User
|
||||
DB.Debug().Where("id = ?", id).First(&user)
|
||||
DB.Where("id = ?", id).First(&user)
|
||||
return user
|
||||
}
|
||||
|
||||
func FindUserByName(name string) User {
|
||||
var user User
|
||||
fmt.Println("name:", name)
|
||||
DB.Debug().Where("name = ?", name).First(&user)
|
||||
DB.Where("name = ?", name).First(&user)
|
||||
return user
|
||||
}
|
||||
|
||||
// 根据name模糊查询,邮箱也是,不查询密码
|
||||
func FindUserByNameLike(name string) []proto.User {
|
||||
var users []proto.User
|
||||
DB.Debug().Where("name LIKE ? OR email LIKE ?", "%"+name+"%", "%"+name+"%").Find(&users).Limit(32)
|
||||
DB.Where("name LIKE ? OR email LIKE ?", "%"+name+"%", "%"+name+"%").Find(&users).Limit(32)
|
||||
return users
|
||||
}
|
||||
|
||||
func FindUserByEmail(email string) User {
|
||||
var user User
|
||||
DB.Debug().Where("email = ?", email).First(&user)
|
||||
DB.Where("email = ?", email).First(&user)
|
||||
return user
|
||||
}
|
||||
|
||||
func UpdateUserByID(id int, name, password, email string) {
|
||||
DB.Model(&User{}).Where("id = ?", id).Updates(User{Name: name, Password: password, Email: email})
|
||||
}
|
||||
|
||||
// 管理员修改用户信息
|
||||
func UpdateUserByID2(id int, req proto.UpdateUserInfoReq) error {
|
||||
updateData := make(map[string]interface{})
|
||||
updateData["Name"] = req.Username
|
||||
updateData["Age"] = req.Age
|
||||
updateData["Role"] = req.Role
|
||||
updateData["Run"] = req.Run
|
||||
updateData["Redis"] = req.Redis
|
||||
updateData["Upload"] = req.Upload
|
||||
updateData["VideoFunc"] = req.VideoFunc
|
||||
updateData["DeviceFunc"] = req.DeviceFunc
|
||||
updateData["CIDFunc"] = req.CIDFunc
|
||||
updateData["Avatar"] = req.Avatar
|
||||
updateData["Gender"] = req.Gender
|
||||
res := DB.Model(&User{}).Where("id =?", id).Updates(updateData)
|
||||
if res.Error != nil {
|
||||
return res.Error
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 用户修改自己的信息
|
||||
func UpdateUserByID3(id int, req proto.UpdateUserInfoReq) error {
|
||||
res := DB.Model(&User{}).Where("id = ?", id).Updates(User{Name: req.Username, Age: req.Age, Avatar: req.Avatar, Gender: req.Gender})
|
||||
return res.Error
|
||||
}
|
||||
|
||||
// 用户数据同步-添加
|
||||
func AddUserSync(req proto.UserAddOrUpdate) uint {
|
||||
res := DB.Exec("insert into users (id, created_at, updated_at, deleted_at, name, age, email, password,gender,role,redis,run,upload,video_func,device_func,cid_func,avatar,create_time,update_time) values (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", req.ID, req.CreatedAt, req.UpdatedAt, req.DeletedAt, req.Name, req.Age, req.Email, req.Password, req.Gender, req.Role, req.Redis, req.Run, req.Upload, req.VideoFunc, req.DeviceFunc, req.CIDFunc, req.Avatar, req.CreateTime, req.UpdateTime)
|
||||
if res.Error != nil {
|
||||
return 0
|
||||
}
|
||||
res = DB.Debug().Exec("update users set deleted_at=null where id=?", req.ID)
|
||||
if res.Error != nil {
|
||||
return 0
|
||||
}
|
||||
return req.ID
|
||||
}
|
||||
|
||||
// 用户数据同步-更新
|
||||
func UpdateUserSync(req proto.UserAddOrUpdate) uint {
|
||||
//事务
|
||||
res := DB.Exec("update users set created_at=?, updated_at=?, deleted_at=?, name=?, age=?, email=?, password=?,gender=?,role=?,redis=?,run=?,upload=?,video_func=?,device_func=?,cid_func=?,avatar=?,create_time=?,update_time=? where id=?", req.CreatedAt, req.UpdatedAt, req.DeletedAt, req.Name, req.Age, req.Email, req.Password, req.Gender, req.Role, req.Redis, req.Run, req.Upload, req.VideoFunc, req.DeviceFunc, req.CIDFunc, req.Avatar, req.CreateTime, req.UpdateTime, req.ID)
|
||||
if res.Error != nil {
|
||||
return 0
|
||||
}
|
||||
res = DB.Debug().Exec("update users set deleted_at=null where id=?", req.ID)
|
||||
if res.Error != nil {
|
||||
return 0
|
||||
}
|
||||
return req.ID
|
||||
}
|
||||
|
||||
// 用户数据同步-删除
|
||||
func DeleteUserSync(req proto.UserDelID) uint {
|
||||
res := DB.Delete(&User{}, req.ID)
|
||||
if res.Error != nil {
|
||||
return 0
|
||||
}
|
||||
return req.ID
|
||||
}
|
||||
|
||||
// 获取所有用户
|
||||
func GetAllUser() []User {
|
||||
var users []User
|
||||
DB.Find(&users)
|
||||
return users
|
||||
}
|
||||
|
||||
// 用户数据同步
|
||||
type UserSyncResp struct {
|
||||
Update []User `json:"update" form:"update"` //更新用户
|
||||
Add []User `json:"add" form:"add"` //添加用户
|
||||
Delete []proto.UserDelID `json:"delete" form:"delete"` //删除用户
|
||||
}
|
||||
|
||||
// 清空用户表
|
||||
func ClearAllUsers() error {
|
||||
res := DB.Exec("TRUNCATE TABLE users")
|
||||
return res.Error
|
||||
}
|
||||
|
|
|
|||
113
dao/video.go
113
dao/video.go
|
|
@ -1,8 +1,9 @@
|
|||
package dao
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"gorm.io/gorm"
|
||||
"time"
|
||||
"videoplayer/proto"
|
||||
)
|
||||
|
||||
type Video struct {
|
||||
|
|
@ -21,35 +22,80 @@ type Video struct {
|
|||
|
||||
func FindWillDelVideoList(id int) []Video {
|
||||
var videos []Video
|
||||
DB.Debug().Where("auth_id = ?", id).Where("delete_time<=now()").Where("isdelete=0").Find(&videos)
|
||||
DB.Raw("select * from videos where auth_id = ? and delete_time<=now() and isdelete=0", id).Scan(&videos)
|
||||
return videos
|
||||
}
|
||||
|
||||
func CreateVideo(videoPath, videoName string, cameraID, authID, human, isDelete int, createTime, endTime, deleteTime string, fileSize int) uint {
|
||||
video := Video{VideoPath: videoPath, VideoName: videoName, CameraID: cameraID, AuthId: authID, Human: human, IsDelete: isDelete, CreateTime: createTime, EndTime: endTime, DeleteTime: deleteTime, FileSize: fileSize}
|
||||
res := DB.Debug().Create(&video)
|
||||
if res.Error != nil {
|
||||
return 0
|
||||
}
|
||||
if deleteTime == "" {
|
||||
DB.Debug().Exec("update videos set delete_time= DATE_ADD(NOW(), INTERVAL 20 DAY) where id=?", video.ID) //delete_time= DATE_ADD(NOW(), INTERVAL 20 DAY)
|
||||
var res *gorm.DB
|
||||
if proto.Config.SERVER_SQL_LOG {
|
||||
res = DB.Debug().Create(&video)
|
||||
if res.Error != nil {
|
||||
return 0
|
||||
}
|
||||
if deleteTime == "" {
|
||||
DB.Debug().Exec("update videos set delete_time= DATE_ADD(NOW(), INTERVAL 20 DAY) where id=?", video.ID) //delete_time= DATE_ADD(NOW(), INTERVAL 20 DAY)
|
||||
}
|
||||
} else {
|
||||
res = DB.Create(&video)
|
||||
if res.Error != nil {
|
||||
return 0
|
||||
}
|
||||
if deleteTime == "" {
|
||||
DB.Exec("update videos set delete_time= DATE_ADD(NOW(), INTERVAL 20 DAY) where id=?", video.ID) //delete_time= DATE_ADD(NOW(), INTERVAL 20 DAY)
|
||||
}
|
||||
}
|
||||
return video.ID
|
||||
}
|
||||
|
||||
// 文件已删除
|
||||
func DeleteVideoByID(id, user int) int {
|
||||
delete_time := time.Now().Format("2006-01-02 15:04:05")
|
||||
DB.Debug().Where("id = ? and auth_id = ?", id, user).Updates(&Video{DeleteTime: delete_time, IsDelete: 1})
|
||||
DB.Debug().Where("id = ? and auth_id = ?", id, user).Delete(&Video{})
|
||||
var res *gorm.DB
|
||||
if proto.Config.SERVER_SQL_LOG {
|
||||
res = DB.Debug().Exec("update videos set deleted_at = now(),isdelete=1 where id=? and auth_id=?", id, user)
|
||||
} else {
|
||||
res = DB.Exec("update videos set deleted_at = now(),isdelete=1 where id=? and auth_id=?", id, user) //delete_time= DATE_ADD(NOW(), INTERVAL 20 DAY)
|
||||
}
|
||||
if res.Error != nil {
|
||||
fmt.Println("dao DeleteVideoByID:", res.Error)
|
||||
return 0
|
||||
}
|
||||
return id
|
||||
}
|
||||
|
||||
// 文件未删除时逻辑删除
|
||||
func LogicDeleteVideoByID(id, user int) int {
|
||||
var res *gorm.DB
|
||||
if proto.Config.SERVER_SQL_LOG {
|
||||
res = DB.Debug().Exec("update videos set deleted_at=now(),delete_time=now() where id=? and auth_id=?", id, user)
|
||||
} else {
|
||||
res = DB.Exec("update videos set deleted_at=now(),delete_time=now() where id=? and auth_id=?", id, user)
|
||||
}
|
||||
if res.Error != nil {
|
||||
fmt.Println("dao LogicDeleteVideoByID:", res.Error)
|
||||
return 0
|
||||
}
|
||||
return id
|
||||
}
|
||||
|
||||
// 回滚视频输出-逻辑删除,若文件已删除则不可回滚
|
||||
func RollbackVideoByID(id, user int) int {
|
||||
res := DB.Exec("update videos set deleted_at=null where id=? and auth_id=? and isdelete=0", id, user) //isdelete=0说明文件未删除
|
||||
if res.Error != nil {
|
||||
fmt.Println("dao RollbackVideoByID:", res.Error)
|
||||
return 0
|
||||
}
|
||||
return id
|
||||
}
|
||||
|
||||
func UpdateVideo(videoPath, videoName string, cameraID, videoID, authID, human, isDelete int, createTime, endTime string, fileSize int) bool {
|
||||
res := DB.Debug().Model(&Video{}).Where("id = ? and auth_id = ?", videoID, authID).Updates(Video{VideoPath: videoPath, VideoName: videoName, CameraID: cameraID, AuthId: authID, Human: human, IsDelete: isDelete, CreateTime: createTime, EndTime: endTime, FileSize: fileSize})
|
||||
if res.Error != nil {
|
||||
return false
|
||||
var res *gorm.DB
|
||||
if proto.Config.SERVER_SQL_LOG {
|
||||
res = DB.Debug().Model(&Video{}).Where("id = ? and auth_id = ?", videoID, authID).Updates(Video{VideoPath: videoPath, VideoName: videoName, CameraID: cameraID, AuthId: authID, Human: human, IsDelete: isDelete, CreateTime: createTime, EndTime: endTime, FileSize: fileSize})
|
||||
} else {
|
||||
res = DB.Model(&Video{}).Where("id = ? and auth_id = ?", videoID, authID).Updates(Video{VideoPath: videoPath, VideoName: videoName, CameraID: cameraID, AuthId: authID, Human: human, IsDelete: isDelete, CreateTime: createTime, EndTime: endTime, FileSize: fileSize})
|
||||
}
|
||||
res = DB.Debug().Exec("update videos set delete_time= DATE_ADD(NOW(), INTERVAL 20 DAY) where id=? and auth_id=?", videoID, authID) //delete_time= DATE_ADD(NOW(), INTERVAL 20 DAY)
|
||||
if res.Error != nil {
|
||||
return false
|
||||
}
|
||||
|
|
@ -58,26 +104,47 @@ func UpdateVideo(videoPath, videoName string, cameraID, videoID, authID, human,
|
|||
|
||||
func FindVideoByID(id, auth_id int) Video {
|
||||
var video Video
|
||||
DB.Debug().Where("id = ? and auth_id = ?", id, auth_id).Where("isdelete = ?", 0).First(&video)
|
||||
DB.Where("id = ? and auth_id = ?", id, auth_id).Where("isdelete = ?", 0).First(&video)
|
||||
return video
|
||||
}
|
||||
|
||||
// 根据用户id查找视频列表,返回最新30条
|
||||
func FindVideoListsByAuthID(auth_id int) []Video {
|
||||
var videos []Video
|
||||
DB.Debug().Where("auth_id = ? and isdelete =? ", auth_id, 0).Order("create_time DESC").Limit(30).Find(&videos)
|
||||
DB.Where("auth_id = ? and isdelete =? ", auth_id, 0).Order("create_time DESC").Limit(30).Find(&videos)
|
||||
return videos
|
||||
}
|
||||
|
||||
// 管理员查找视频,可查找所有视频
|
||||
func FindVideoByID2(id int) []Video {
|
||||
var videos []Video
|
||||
var err error
|
||||
if proto.Config.SERVER_SQL_LOG {
|
||||
res := DB.Debug().Raw("select * from videos where id = ?", id).Scan(&videos)
|
||||
err = res.Error
|
||||
} else {
|
||||
res := DB.Raw("select * from videos where id = ?", id).Scan(&videos)
|
||||
err = res.Error
|
||||
}
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return videos
|
||||
}
|
||||
|
||||
func FindVideoListByTime(auth_id int, startTime, endTime string) []Video {
|
||||
var videos []Video
|
||||
DB.Debug().Where("auth_id = ?", auth_id).Where("isdelete=0").Where("create_time > ? and create_time < ?", startTime, endTime).Find(&videos)
|
||||
if proto.Config.SERVER_SQL_LOG {
|
||||
DB.Debug().Where("auth_id = ?", auth_id).Where("create_time > ? and create_time < ? and isdelete=0", startTime, endTime).Find(&videos)
|
||||
} else {
|
||||
DB.Where("auth_id = ?", auth_id).Where("create_time > ? and create_time < ? and isdelete=0", startTime, endTime).Find(&videos)
|
||||
}
|
||||
return videos
|
||||
}
|
||||
|
||||
// id 为视频id,auth_id为用户id,day为延长天数,返回修改的行数
|
||||
func DelayVideo(id, auth_id, day int) int {
|
||||
res := DB.Debug().Exec("update videos set delete_time = date_add(delete_time, interval ? day) where id = ? and auth_id = ? and isdelete=0", day, id, auth_id)
|
||||
res := DB.Exec("update videos set delete_time = date_add(delete_time, interval ? day) where id = ? and auth_id = ? and isdelete=0", day, id, auth_id)
|
||||
if res.Error != nil {
|
||||
return 0
|
||||
}
|
||||
|
|
@ -86,7 +153,7 @@ func DelayVideo(id, auth_id, day int) int {
|
|||
|
||||
// id 为用户id,day为延长天数,返回修改的行数
|
||||
func DelayAllVideo(id, day int) int {
|
||||
res := DB.Debug().Exec("update videos set delete_time = date_add(delete_time, interval ? day) where auth_id = ? and isdelete = 0", day, id)
|
||||
res := DB.Exec("update videos set delete_time = date_add(delete_time, interval ? day) where auth_id = ? and isdelete = 0", day, id)
|
||||
if res.Error != nil {
|
||||
return 0
|
||||
}
|
||||
|
|
@ -94,7 +161,7 @@ func DelayAllVideo(id, day int) int {
|
|||
}
|
||||
|
||||
func QuashOneDelay(id, user_id int, day int) int {
|
||||
res := DB.Debug().Exec("update videos set delete_time = date_sub(delete_time, interval ? day) where id = ? and auth_id = ? and isdelete=0", day, id, user_id)
|
||||
res := DB.Exec("update videos set delete_time = date_sub(delete_time, interval ? day) where id = ? and auth_id = ? and isdelete=0", day, id, user_id)
|
||||
if res.Error != nil {
|
||||
return 0
|
||||
}
|
||||
|
|
@ -102,7 +169,7 @@ func QuashOneDelay(id, user_id int, day int) int {
|
|||
}
|
||||
|
||||
func QuashAllDelay(user_id int, day int) int {
|
||||
res := DB.Debug().Exec("update videos set delete_time = date_sub(delete_time, interval ? day) where auth_id = ? and isdelete=0", day, user_id)
|
||||
res := DB.Exec("update videos set delete_time = date_sub(delete_time, interval ? day) where auth_id = ? and isdelete=0", day, user_id)
|
||||
if res.Error != nil {
|
||||
return 0
|
||||
}
|
||||
|
|
@ -112,6 +179,6 @@ func QuashAllDelay(user_id int, day int) int {
|
|||
// 获取视频列表分页
|
||||
func GetVideoListByPage(auth_id, page, pageSize int) []Video {
|
||||
var videos []Video
|
||||
DB.Debug().Where("auth_id = ? and isdelete = ?", auth_id, 0).Order("create_time DESC").Offset((page - 1) * pageSize).Limit(pageSize).Find(&videos) //Offset((page - 1) * pageSize).Limit(pageSize),分页,page从1开始,pageSize每页多少条,Offset是偏移量,Limit是限制条数
|
||||
DB.Where("auth_id = ? and isdelete = ?", auth_id, 0).Order("created_at DESC").Offset((page - 1) * pageSize).Limit(pageSize).Find(&videos) //Offset((page - 1) * pageSize).Limit(pageSize),分页,page从1开始,pageSize每页多少条,Offset是偏移量,Limit是限制条数
|
||||
return videos
|
||||
}
|
||||
|
|
|
|||
15
go.mod
15
go.mod
|
|
@ -8,8 +8,10 @@ require (
|
|||
github.com/golang-jwt/jwt v3.2.2+incompatible
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/gorilla/websocket v1.5.3
|
||||
github.com/robfig/cron/v3 v3.0.1
|
||||
gorm.io/driver/mysql v1.5.6
|
||||
gorm.io/gorm v1.25.7
|
||||
gorm.io/driver/postgres v1.5.9
|
||||
gorm.io/gorm v1.30.0
|
||||
)
|
||||
|
||||
require (
|
||||
|
|
@ -26,22 +28,31 @@ require (
|
|||
github.com/go-playground/validator/v10 v10.20.0 // indirect
|
||||
github.com/go-sql-driver/mysql v1.7.0 // indirect
|
||||
github.com/goccy/go-json v0.10.2 // indirect
|
||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
|
||||
github.com/jackc/pgx/v5 v5.5.5 // indirect
|
||||
github.com/jackc/puddle/v2 v2.2.1 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/jinzhu/now v1.1.5 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/leodido/go-urn v1.4.0 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mattn/go-sqlite3 v1.14.22 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
||||
github.com/rogpeppe/go-internal v1.12.0 // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/ugorji/go/codec v1.2.12 // indirect
|
||||
golang.org/x/arch v0.8.0 // indirect
|
||||
golang.org/x/crypto v0.23.0 // indirect
|
||||
golang.org/x/net v0.25.0 // indirect
|
||||
golang.org/x/sync v0.9.0 // indirect
|
||||
golang.org/x/sys v0.20.0 // indirect
|
||||
golang.org/x/text v0.15.0 // indirect
|
||||
golang.org/x/text v0.20.0 // indirect
|
||||
google.golang.org/protobuf v1.34.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
gorm.io/driver/sqlite v1.6.0 // indirect
|
||||
)
|
||||
|
|
|
|||
37
go.sum
37
go.sum
|
|
@ -8,6 +8,7 @@ github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/
|
|||
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
|
||||
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
|
||||
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
|
|
@ -44,6 +45,14 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
|||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
|
||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||
github.com/jackc/pgx/v5 v5.5.5 h1:amBjrZVmksIdNjxGW/IiIMzxMKZFelXbUoPNb+8sjQw=
|
||||
github.com/jackc/pgx/v5 v5.5.5/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A=
|
||||
github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
|
||||
github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
||||
|
|
@ -54,10 +63,16 @@ github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa02
|
|||
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
|
||||
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
|
||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
||||
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
|
||||
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
|
|
@ -73,6 +88,10 @@ github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6
|
|||
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
||||
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
||||
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
||||
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
|
|
@ -96,18 +115,25 @@ golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
|
|||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ=
|
||||
golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug=
|
||||
golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
|
||||
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
|
|
@ -117,7 +143,14 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
|||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gorm.io/driver/mysql v1.5.6 h1:Ld4mkIickM+EliaQZQx3uOJDJHtrd70MxAUqWqlx3Y8=
|
||||
gorm.io/driver/mysql v1.5.6/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM=
|
||||
gorm.io/gorm v1.25.7 h1:VsD6acwRjz2zFxGO50gPO6AkNs7KKnvfzUjHQhZDz/A=
|
||||
gorm.io/driver/postgres v1.5.9 h1:DkegyItji119OlcaLjqN11kHoUgZ/j13E0jkJZgD6A8=
|
||||
gorm.io/driver/postgres v1.5.9/go.mod h1:DX3GReXH+3FPWGrrgffdvCk3DQ1dwDPdmbenSkweRGI=
|
||||
gorm.io/driver/sqlite v1.6.0 h1:WHRRrIiulaPiPFmDcod6prc4l2VGVWHz80KspNsxSfQ=
|
||||
gorm.io/driver/sqlite v1.6.0/go.mod h1:AO9V1qIQddBESngQUKWL9yoH93HIeA1X6V633rBwyT8=
|
||||
gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
|
||||
gorm.io/gorm v1.25.10 h1:dQpO+33KalOA+aFYGlK+EfxcI5MbO7EP2yYygwh9h+s=
|
||||
gorm.io/gorm v1.25.10/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
|
||||
gorm.io/gorm v1.30.0 h1:qbT5aPv1UH8gI99OsRlvDToLxW5zR7FzS9acZDOZcgs=
|
||||
gorm.io/gorm v1.30.0/go.mod h1:8Z33v652h4//uMA76KjeDH8mJXPm1QNCYrMeatR0DOE=
|
||||
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
|
||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||
|
|
|
|||
285
handler/cid.go
285
handler/cid.go
|
|
@ -2,18 +2,24 @@ package handler
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"videoplayer/dao"
|
||||
"videoplayer/proto"
|
||||
"videoplayer/service"
|
||||
"videoplayer/worker"
|
||||
)
|
||||
|
||||
type CIDCreateReq struct {
|
||||
Name string `json:"name" form:"name"`
|
||||
Url string `json:"url" form:"url"`
|
||||
Time int `json:"time" form:"time"` // 定时任务,单位秒,大于0表示定时任务
|
||||
Script string `json:"script" form:"script"`
|
||||
}
|
||||
|
||||
|
|
@ -33,10 +39,14 @@ type CIDUpdateReq struct {
|
|||
ID int `json:"id" form:"id"`
|
||||
Name string `json:"name" form:"name"`
|
||||
Url string `json:"url" form:"url"`
|
||||
Time int `json:"time" form:"time"` // 定时任务,单位秒,大于0表示定时任务
|
||||
Script string `json:"script" form:"script"`
|
||||
Token string `json:"cidtoken" form:"cidtoken"`
|
||||
}
|
||||
|
||||
// 全局变量,记录是否进行cron定时任务的刷新
|
||||
var cron_count int
|
||||
|
||||
func SetUpCIDGroup(router *gin.Engine) {
|
||||
cidGroup := router.Group("/cid") //持续集成、部署
|
||||
cidGroup.POST("/create", CreateCID)
|
||||
|
|
@ -46,28 +56,50 @@ func SetUpCIDGroup(router *gin.Engine) {
|
|||
cidGroup.POST("/run", RunCID)
|
||||
cidGroup.POST("/log", GetCIDLogList) //获取执行日志
|
||||
cidGroup.POST("/log/detail", GetCIDLog) //获取执行日志详情
|
||||
cidGroup.GET("/callback", CIDCallback)
|
||||
cidGroup.POST("/callback", CIDCallback)
|
||||
cidGroup.GET("/running", GetRunningCIDs)
|
||||
}
|
||||
func GetRunningCIDs(c *gin.Context) {
|
||||
id, _ := c.Get("id")
|
||||
user_id := int(id.(float64))
|
||||
req_type := c.Query("type") //请求方式 0默认自己, 1为所有(管理员可选)
|
||||
req_type_ := 0
|
||||
if req_type != "" {
|
||||
req_type_, _ = strconv.Atoi(req_type)
|
||||
}
|
||||
resp_data, err := service.GetCIDRunningList(user_id, req_type_)
|
||||
|
||||
var resp proto.GeneralResp
|
||||
if err != nil {
|
||||
resp.Code = proto.InternalServerError
|
||||
resp.Message = err.Error()
|
||||
} else {
|
||||
resp.Code, resp.Message = 0, ""
|
||||
resp.Data = resp_data
|
||||
}
|
||||
c.JSON(http.StatusOK, resp)
|
||||
}
|
||||
func RunCID(c *gin.Context) {
|
||||
var req CIDRunReq
|
||||
id, _ := c.Get("id")
|
||||
authID := int(id.(float64))
|
||||
//获取权限
|
||||
user := dao.FindUserByUserID(authID)
|
||||
if user.Run == false {
|
||||
//user := dao.FindUserByUserID(authID)
|
||||
user := service.GetUserByIDFromUserCenter(authID)
|
||||
if user.Run <= 0 {
|
||||
c.JSON(200, gin.H{"error": "no run Permissions", "code": proto.NoRunPermissions, "message": "no run Permissions"})
|
||||
return
|
||||
}
|
||||
|
||||
if err := c.ShouldBind(&req); err == nil {
|
||||
// 获取用户ID
|
||||
username, _ := c.Get("username")
|
||||
cid := dao.FindCIDByID(req.ID, authID)
|
||||
if cid.ID == 0 {
|
||||
c.JSON(200, gin.H{"error": "CID not found", "code": proto.OperationFailed, "message": "failed"})
|
||||
return
|
||||
} else {
|
||||
go RunShell(username.(string), cid.Url, cid.Script, req.ID, authID)
|
||||
go RunShellCID(cid.Name, cid.Url, cid.Script, req.ID, authID)
|
||||
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "success", "data": "success"})
|
||||
}
|
||||
} else {
|
||||
|
|
@ -82,9 +114,11 @@ func CreateCID(c *gin.Context) {
|
|||
id, _ := c.Get("id")
|
||||
authID := int(id.(float64))
|
||||
token, _ := generateRandomHexString(32)
|
||||
|
||||
res := dao.CreateCID(req.Name, req.Url, req.Script, token, authID)
|
||||
res := dao.CreateCID(req.Name, req.Url, req.Script, token, req.Time, authID)
|
||||
if res != 0 {
|
||||
if req.Time > 0 {
|
||||
updateCronRedisTime(int(res), req.Time)
|
||||
}
|
||||
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "success", "data": res})
|
||||
} else {
|
||||
c.JSON(200, gin.H{"error": "CreateCID failed", "code": proto.OperationFailed, "message": "failed"})
|
||||
|
|
@ -118,11 +152,14 @@ func UpdateCID(c *gin.Context) {
|
|||
// 获取用户ID
|
||||
id, _ := c.Get("id")
|
||||
authID := int(id.(float64))
|
||||
cid := dao.UpdateCIDByID(req.ID, authID, req.Name, req.Url, req.Script, req.Token)
|
||||
cid := dao.UpdateCIDByID(req.ID, authID, req.Time, req.Name, req.Url, req.Script, req.Token)
|
||||
if cid == false {
|
||||
c.JSON(200, gin.H{"error": "CID not found", "code": proto.OperationFailed, "message": "failed"})
|
||||
return
|
||||
} else {
|
||||
if req.Time > 0 {
|
||||
updateCronRedisTime(req.ID, req.Time)
|
||||
}
|
||||
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "success", "data": "success"})
|
||||
}
|
||||
} else {
|
||||
|
|
@ -169,31 +206,43 @@ func CIDCallback(c *gin.Context) {
|
|||
// 获取用户ID
|
||||
token := c.Query("token")
|
||||
cid_id := c.Query("id")
|
||||
fmt.Println("token:", token, "cid_id:", cid_id)
|
||||
//将cid转换为int
|
||||
cid, _ := strconv.Atoi(cid_id)
|
||||
|
||||
if token == "" || cid == 0 {
|
||||
c.JSON(200, gin.H{"error": "parameter error", "code": proto.ParameterError, "message": "failed"})
|
||||
var req proto.CIDCallBackReq
|
||||
var resp proto.GeneralResp
|
||||
if err := c.ShouldBindQuery(&req); err != nil {
|
||||
resp.Code, resp.Message = proto.ParameterError, err.Error()
|
||||
c.JSON(http.StatusOK, resp)
|
||||
return
|
||||
}
|
||||
if req.ID == 0 || req.Token == "" {
|
||||
resp.Code, resp.Message = proto.ParameterError, "token or id is empty"
|
||||
c.JSON(http.StatusOK, resp)
|
||||
return
|
||||
}
|
||||
|
||||
res := dao.FindCIDByIDAndToken(cid, token)
|
||||
if res.ID == 0 {
|
||||
c.JSON(200, gin.H{"error": "CID not found by id and token", "code": proto.OperationFailed, "message": "failed"})
|
||||
resp.Code, resp.Message = proto.ParameterError, "CID not found by id and token:"+req.Token+", id:"+strconv.Itoa(int(res.ID))
|
||||
c.JSON(http.StatusOK, resp)
|
||||
return
|
||||
}
|
||||
|
||||
user := dao.FindUserByUserID(res.Auth_id)
|
||||
if user.Run == false {
|
||||
c.JSON(200, gin.H{"error": "no run Permissions", "code": proto.NoRunPermissions, "message": "the user has no run Permissions"})
|
||||
//user := dao.FindUserByUserID(res.Auth_id)
|
||||
user := service.GetUserByIDFromUserCenter(res.Auth_id)
|
||||
if user.Run <= 0 {
|
||||
resp.Code, resp.Message = proto.NoRunPermissions, "the user has no run Permissions"
|
||||
c.JSON(http.StatusOK, resp)
|
||||
return
|
||||
}
|
||||
if res.ID != 0 {
|
||||
user := dao.FindUserByID(res.Auth_id)
|
||||
go RunShell(user[0].Name, res.Url, res.Script, int(res.ID), res.Auth_id)
|
||||
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "success", "data": "success"})
|
||||
go RunShellCID(res.Name, res.Url, res.Script, int(res.ID), res.Auth_id)
|
||||
resp.Code, resp.Message, resp.Data = proto.SuccessCode, "success", res.Name
|
||||
c.JSON(http.StatusOK, resp)
|
||||
return
|
||||
} else {
|
||||
c.JSON(200, gin.H{"error": "CID not found by id and token", "code": proto.OperationFailed, "message": "failed"})
|
||||
resp.Code, resp.Message = proto.OperationFailed, "CID not found by id and token"
|
||||
c.JSON(http.StatusOK, resp)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
|
@ -203,12 +252,12 @@ func RunShell(username, url, script string, id, authID int) {
|
|||
name := strs[len(strs)-1]
|
||||
names := strings.Split(name, ".")
|
||||
name = names[0]
|
||||
|
||||
//脚本内容,不同用户的持续集成、部署目录不同
|
||||
scriptContent := `
|
||||
echo "start"
|
||||
` + script + `
|
||||
echo "end"`
|
||||
start := time.Now()
|
||||
//执行脚本
|
||||
cmd := exec.Command("/bin/bash", "-c", scriptContent)
|
||||
// 使用bytes.Buffer捕获输出
|
||||
|
|
@ -219,6 +268,198 @@ echo "end"`
|
|||
if err3 != nil {
|
||||
err3_info = err3.Error()
|
||||
}
|
||||
fmt.Println("bash content:", scriptContent)
|
||||
dao.CreateRunLog(id, authID, scriptContent, out.String(), err3_info) //添加执行日志
|
||||
elapsed := time.Since(start)
|
||||
//fmt.Println("bash content:", scriptContent)
|
||||
dao.CreateRunLog(id, authID, scriptContent, out.String(), err3_info, elapsed.Seconds()) //添加执行日志
|
||||
}
|
||||
|
||||
func RunShellCID(cid_name, url, script string, id, authID int) {
|
||||
strs := strings.Split(url, "/")
|
||||
name := strs[len(strs)-1]
|
||||
names := strings.Split(name, ".")
|
||||
name = names[0]
|
||||
now := time.Now()
|
||||
var cid_running proto.CIDRunning
|
||||
cid_running.ID = id
|
||||
cid_running.AuthID = authID
|
||||
cid_running.StartTime = now
|
||||
cid_running.CID = cid_name
|
||||
//加入正在运行
|
||||
proto.CID_RunningMutex.Lock()
|
||||
user_running_list := proto.CID_Running_Map[authID]
|
||||
user_running_list = append(user_running_list, cid_running)
|
||||
proto.CID_Running_Map[authID] = user_running_list
|
||||
proto.CID_RunningMutex.Unlock()
|
||||
|
||||
//脚本内容,不同用户的持续集成、部署目录不同
|
||||
scriptContent := `
|
||||
echo "start"
|
||||
` + script + `
|
||||
echo "end"`
|
||||
start := time.Now()
|
||||
//执行脚本
|
||||
cmd := exec.Command("/bin/bash", "-c", scriptContent)
|
||||
// 使用bytes.Buffer捕获输出
|
||||
var out bytes.Buffer
|
||||
cmd.Stdout = &out
|
||||
err3 := cmd.Run()
|
||||
err3_info := ""
|
||||
if err3 != nil {
|
||||
err3_info = err3.Error()
|
||||
}
|
||||
elapsed := time.Since(start)
|
||||
//fmt.Println("bash content:", scriptContent)
|
||||
dao.CreateRunLog(id, authID, scriptContent, out.String(), err3_info, elapsed.Seconds()) //添加执行日志
|
||||
if err3 != nil {
|
||||
dao.UpdateLastFailByID(id, time.Now())
|
||||
} else {
|
||||
dao.UpdateLastSuccessByID(id, time.Now())
|
||||
}
|
||||
//移除正在运行
|
||||
proto.CID_RunningMutex.Lock()
|
||||
user_running_list = proto.CID_Running_Map[authID]
|
||||
for i, v := range user_running_list {
|
||||
if v.StartTime.Equal(now) == true {
|
||||
//删除
|
||||
user_running_list = append(user_running_list[:i], user_running_list[i+1:]...)
|
||||
break
|
||||
}
|
||||
}
|
||||
proto.CID_Running_Map[authID] = user_running_list
|
||||
proto.CID_RunningMutex.Unlock()
|
||||
}
|
||||
|
||||
// 定时任务处理逻辑
|
||||
func RunCron() {
|
||||
cron_count++
|
||||
if cron_count > 6 {
|
||||
updateCronFromDBToRedis()
|
||||
cron_count = 0
|
||||
}
|
||||
//从redis查看是否有定时任务
|
||||
//如果有定时任务,执行定时任务
|
||||
//如果没有定时任务,查找数据库是否有定时任务,如果有,则加入redis,如果没有,则不做任何操作
|
||||
key := "cron_cid_runs"
|
||||
res := worker.GetRedis(key)
|
||||
//fmt.Println("cid run cron res:", res)
|
||||
if res == "" {
|
||||
readCronFromDBToRedis(key)
|
||||
} else {
|
||||
var cid_workers []proto.CIDRUN
|
||||
err := json.Unmarshal([]byte(res), &cid_workers)
|
||||
if err != nil {
|
||||
fmt.Println("json unmarshal failed")
|
||||
}
|
||||
//fmt.Println("cid_workers:", cid_workers)
|
||||
for i, v := range cid_workers {
|
||||
//查找定时任务
|
||||
if v.Curr-10 <= 0 {
|
||||
cid := dao.FindCIDByCID(v.CID)
|
||||
if cid.ID != 0 {
|
||||
go RunShell("cron", cid.Url, cid.Script, int(cid.ID), cid.Auth_id)
|
||||
}
|
||||
cid_workers[i].Curr = v.Every
|
||||
} else {
|
||||
cid_workers[i].Curr = v.Curr - 10
|
||||
}
|
||||
}
|
||||
//将定时任务加入redis
|
||||
json_data, err := json.Marshal(cid_workers)
|
||||
if err != nil {
|
||||
fmt.Println("json marshal failed")
|
||||
}
|
||||
worker.SetRedis(key, string(json_data))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 将数据库中的定时任务加入redis
|
||||
func readCronFromDBToRedis(key string) {
|
||||
cids := dao.FindCIDByTime()
|
||||
cid_workers := make([]proto.CIDRUN, 0)
|
||||
for _, v := range cids {
|
||||
cid_worker := proto.CIDRUN{CID: v.ID, Curr: v.Time, Every: v.Time}
|
||||
cid_workers = append(cid_workers, cid_worker)
|
||||
}
|
||||
if len(cid_workers) > 0 {
|
||||
//将定时任务加入redis
|
||||
json_data, err := json.Marshal(cid_workers)
|
||||
if err != nil {
|
||||
fmt.Println("json marshal failed")
|
||||
}
|
||||
worker.SetRedis(key, string(json_data))
|
||||
}
|
||||
}
|
||||
|
||||
// 从数据库更新定时任务到redis
|
||||
func updateCronFromDBToRedis() {
|
||||
key := "cron_cid_runs"
|
||||
cids := dao.FindCIDByTime()
|
||||
cid_maps := make(map[uint]int)
|
||||
|
||||
//将数据库中的定时任务加入map,key为cid,value为时间,便于后续查找
|
||||
for _, v := range cids {
|
||||
cid_maps[v.ID] = v.Time
|
||||
}
|
||||
res := worker.GetRedis(key)
|
||||
if res == "" {
|
||||
readCronFromDBToRedis(key)
|
||||
return
|
||||
}
|
||||
var cid_workers_redis []proto.CIDRUN
|
||||
err := json.Unmarshal([]byte(res), &cid_workers_redis)
|
||||
if err != nil {
|
||||
fmt.Println("json unmarshal failed")
|
||||
return
|
||||
}
|
||||
for i, v := range cid_workers_redis {
|
||||
if time, ok := cid_maps[v.CID]; ok {
|
||||
if v.Every != time {
|
||||
cid_workers_redis[i].Every = time
|
||||
cid_workers_redis[i].Curr = time
|
||||
}
|
||||
}
|
||||
}
|
||||
//将定时任务加入redis
|
||||
json_data, err := json.Marshal(cid_workers_redis)
|
||||
if err != nil {
|
||||
fmt.Println("json marshal failed")
|
||||
return
|
||||
}
|
||||
worker.SetRedis(key, string(json_data))
|
||||
}
|
||||
|
||||
// 查看指定定时任务是否存在,如果存在则更新时间,如果不存在则加入
|
||||
func updateCronRedisTime(id int, time int) {
|
||||
key := "cron_cid_runs"
|
||||
res := worker.GetRedis(key)
|
||||
if res == "" {
|
||||
readCronFromDBToRedis(key)
|
||||
return
|
||||
} else {
|
||||
var cid_workers []proto.CIDRUN
|
||||
err := json.Unmarshal([]byte(res), &cid_workers)
|
||||
if err != nil {
|
||||
fmt.Println("json unmarshal failed")
|
||||
}
|
||||
isContain := false
|
||||
for i, v := range cid_workers {
|
||||
if v.CID == uint(id) {
|
||||
//更新时间,不会继续原来的时间
|
||||
cid_workers[i].Curr = time
|
||||
cid_workers[i].Every = time
|
||||
isContain = true
|
||||
}
|
||||
}
|
||||
if isContain == false {
|
||||
cid_worker := proto.CIDRUN{CID: uint(id), Curr: time, Every: time}
|
||||
cid_workers = append(cid_workers, cid_worker)
|
||||
}
|
||||
//将定时任务加入redis
|
||||
json_data, err := json.Marshal(cid_workers)
|
||||
if err != nil {
|
||||
fmt.Println("json marshal failed")
|
||||
}
|
||||
worker.SetRedis(key, string(json_data))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,23 +1,23 @@
|
|||
package handler
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
//"net/http"
|
||||
)
|
||||
|
||||
//跨域访问:cross origin resource share
|
||||
func CrosHandler() gin.HandlerFunc {
|
||||
return func(context *gin.Context) {
|
||||
//method := context.Request.Method
|
||||
context.Writer.Header().Set("Access-Control-Allow-Origin", "*")
|
||||
context.Header("Access-Control-Allow-Origin", "*") // 设置允许访问所有域
|
||||
context.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE,UPDATE")
|
||||
context.Header("Access-Control-Allow-Headers", "Authorization, Content-Length, X-CSRF-Token, Token,session,X_Requested_With,Accept, Origin, Host, Connection, Accept-Encoding, Accept-Language,DNT, X-CustomHeader, Keep-Alive, User-Agent, X-Requested-With, If-Modified-Since, Cache-Control, Content-Type, Pragma,token,openid,opentoken")
|
||||
context.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers,Cache-Control,Content-Language,Content-Type,Expires,Last-Modified,Pragma,FooBar")
|
||||
context.Header("Access-Control-Max-Age", "172800")
|
||||
context.Header("Access-Control-Allow-Credentials", "false")
|
||||
context.Set("content-type", "application/json") //设置返回格式是json
|
||||
|
||||
package handler
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
//"net/http"
|
||||
)
|
||||
|
||||
// 跨域访问:cross origin resource share
|
||||
func CrosHandler() gin.HandlerFunc {
|
||||
return func(context *gin.Context) {
|
||||
//method := context.Request.Method
|
||||
context.Writer.Header().Set("Access-Control-Allow-Origin", "*")
|
||||
context.Header("Access-Control-Allow-Origin", "*") // 设置允许访问所有域
|
||||
context.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE,UPDATE")
|
||||
context.Header("Access-Control-Allow-Headers", "Authorization, Content-Length, X-CSRF-Token, Token,session,X_Requested_With,Accept, Origin, Host, Connection, Accept-Encoding, Accept-Language,DNT, X-CustomHeader, Keep-Alive, User-Agent, X-Requested-With, If-Modified-Since, Cache-Control, Content-Type, Pragma,token,openid,opentoken")
|
||||
context.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers,Cache-Control,Content-Language,Content-Type,Expires,Last-Modified,Pragma,FooBar")
|
||||
context.Header("Access-Control-Max-Age", "172800")
|
||||
context.Header("Access-Control-Allow-Credentials", "false")
|
||||
context.Set("content-type", "application/json") //设置返回格式是json
|
||||
|
||||
// if method == "OPTIONS" {
|
||||
// context.JSON(http.StatusOK, gin.H{
|
||||
// "code":1,
|
||||
|
|
@ -25,8 +25,8 @@
|
|||
// "data":"request error",
|
||||
// })
|
||||
// }
|
||||
|
||||
//处理请求
|
||||
context.Next()
|
||||
}
|
||||
}
|
||||
|
||||
//处理请求
|
||||
context.Next()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,208 @@
|
|||
package handler
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"log"
|
||||
"net/http"
|
||||
"videoplayer/proto"
|
||||
"videoplayer/service"
|
||||
)
|
||||
|
||||
func SetDBManageGroup(router *gin.Engine) {
|
||||
dbm := router.Group("/dbm")
|
||||
|
||||
dbm.POST("/run_sql", RunSQLHandler) // 运行SQL语句
|
||||
dbm.POST("/create_db_manage", CreateDBManageHandler) // 创建数据库管理
|
||||
dbm.POST("/get_db_manage", GetDBManageHandler) // 获取数据库管理信息
|
||||
dbm.POST("/get_sql_history", GetSQLRunHistoryHandler) // 获取SQL运行历史
|
||||
dbm.POST("/update_db_manage", UpdateDBManageHandler) // 更新数据库管理信息
|
||||
dbm.POST("/del_db_manage", DeleteDBManageHandler) // 删除数据库管理信息
|
||||
dbm.POST("/del_dbm_sql_history", DeleteSQLRunHistoryHandler) // 删除SQL运行历史
|
||||
dbm.POST("/get_db_table_desc", GetDBTableDescHandler) // 获取数据库表描述
|
||||
}
|
||||
|
||||
func DeleteSQLRunHistoryHandler(c *gin.Context) {
|
||||
id, _ := c.Get("id")
|
||||
userID := int(id.(float64))
|
||||
|
||||
var req proto.DeleteDBManageSQLHistoryReq
|
||||
var resp proto.GeneralResp
|
||||
if err := c.ShouldBind(&req); err != nil {
|
||||
resp.Code = proto.ParameterError
|
||||
resp.Message = "请求参数解析错误"
|
||||
} else {
|
||||
err2 := service.DeleteSQLRunHistory(&req, userID)
|
||||
if err2 != nil {
|
||||
resp.Code = proto.DBMRunSQLHistoryDeleteFailed
|
||||
resp.Message = "删除SQL运行历史失败: " + err2.Error()
|
||||
} else {
|
||||
resp.Code = proto.SuccessCode
|
||||
resp.Message = "删除SQL运行历史成功"
|
||||
}
|
||||
}
|
||||
c.JSON(http.StatusOK, resp)
|
||||
|
||||
}
|
||||
|
||||
func DeleteDBManageHandler(c *gin.Context) {
|
||||
id, _ := c.Get("id")
|
||||
userID := int(id.(float64))
|
||||
|
||||
var req proto.DeleteDBManageReq
|
||||
var resp proto.GeneralResp
|
||||
if err := c.ShouldBind(&req); err != nil {
|
||||
resp.Code = proto.ParameterError
|
||||
resp.Message = "请求参数解析错误"
|
||||
} else {
|
||||
err2 := service.DeleteDBManage(&req, userID)
|
||||
if err2 != nil {
|
||||
resp.Code = proto.DBMDeleteFailed
|
||||
resp.Message = "删除数据库管理失败: " + err2.Error()
|
||||
} else {
|
||||
resp.Code = proto.SuccessCode
|
||||
resp.Message = "删除数据库管理成功"
|
||||
}
|
||||
}
|
||||
c.JSON(http.StatusOK, resp)
|
||||
}
|
||||
|
||||
func UpdateDBManageHandler(c *gin.Context) {
|
||||
id, _ := c.Get("id")
|
||||
userID := int(id.(float64))
|
||||
|
||||
var req proto.UpdateDBManageReq
|
||||
var resp proto.GeneralResp
|
||||
if err := c.ShouldBind(&req); err != nil {
|
||||
resp.Code = proto.ParameterError
|
||||
resp.Message = "请求参数解析错误"
|
||||
} else {
|
||||
dbManage, err2 := service.UpdateDBManage(&req, userID)
|
||||
if err2 != nil {
|
||||
resp.Code = proto.DBMUpdateFailed
|
||||
resp.Message = "更新数据库管理失败: " + err2.Error()
|
||||
} else {
|
||||
resp.Code = proto.SuccessCode
|
||||
resp.Message = "更新数据库管理成功"
|
||||
resp.Data = dbManage
|
||||
}
|
||||
}
|
||||
c.JSON(http.StatusOK, resp)
|
||||
}
|
||||
|
||||
func GetSQLRunHistoryHandler(c *gin.Context) {
|
||||
id, _ := c.Get("id")
|
||||
userID := int(id.(float64))
|
||||
|
||||
var req proto.GetSQLRunHistoryReq
|
||||
var resp proto.GeneralResp
|
||||
if err := c.ShouldBind(&req); err != nil {
|
||||
resp.Code = proto.ParameterError
|
||||
resp.Message = "请求参数解析错误"
|
||||
} else {
|
||||
history, err2 := service.GetSQLRunHistory(&req, userID)
|
||||
if err2 != nil {
|
||||
resp.Code = proto.DBMGetFailed
|
||||
resp.Message = "获取SQL运行历史失败: " + err2.Error()
|
||||
} else {
|
||||
resp.Code = proto.SuccessCode
|
||||
resp.Message = "获取SQL运行历史成功"
|
||||
resp.Data = history
|
||||
}
|
||||
}
|
||||
c.JSON(http.StatusOK, resp)
|
||||
}
|
||||
|
||||
func GetDBManageHandler(c *gin.Context) {
|
||||
id, _ := c.Get("id")
|
||||
userID := uint(id.(float64))
|
||||
|
||||
var req proto.GetDBManageReq
|
||||
var resp proto.GeneralResp
|
||||
if err := c.ShouldBind(&req); err != nil {
|
||||
resp.Code = proto.ParameterError
|
||||
resp.Message = "请求参数解析错误"
|
||||
} else {
|
||||
dbManage, err2 := service.GetDBManageList(&req, userID)
|
||||
if err2 != nil {
|
||||
resp.Code = proto.DBMGetFailed
|
||||
resp.Message = "获取数据库管理信息失败: " + err2.Error()
|
||||
} else {
|
||||
resp.Code = proto.SuccessCode
|
||||
resp.Message = "获取数据库管理信息成功"
|
||||
resp.Data = dbManage
|
||||
}
|
||||
}
|
||||
c.JSON(http.StatusOK, resp)
|
||||
}
|
||||
|
||||
func CreateDBManageHandler(c *gin.Context) {
|
||||
id, _ := c.Get("id")
|
||||
userID := uint(id.(float64))
|
||||
|
||||
var req proto.CreateDBManageReq
|
||||
var resp proto.GeneralResp
|
||||
if err := c.ShouldBind(&req); err != nil {
|
||||
resp.Code = proto.ParameterError
|
||||
resp.Message = "请求参数解析错误"
|
||||
} else {
|
||||
dbManage, err2 := service.CreateDBManage(&req, userID)
|
||||
if err2 != nil {
|
||||
resp.Code = proto.DBMCreateFailed
|
||||
resp.Message = "创建数据库管理失败: " + err.Error()
|
||||
} else {
|
||||
resp.Code = proto.SuccessCode
|
||||
resp.Message = "创建数据库管理成功"
|
||||
resp.Data = dbManage
|
||||
}
|
||||
}
|
||||
c.JSON(http.StatusOK, resp)
|
||||
}
|
||||
|
||||
func RunSQLHandler(c *gin.Context) {
|
||||
id, _ := c.Get("id")
|
||||
userID := uint(id.(float64))
|
||||
// 处理运行SQL请求
|
||||
var req proto.RunSQLRequest
|
||||
var resp proto.GeneralResp
|
||||
if err := c.ShouldBind(&req); err != nil {
|
||||
resp.Code = proto.ParameterError
|
||||
resp.Message = "请求参数解析错误"
|
||||
} else {
|
||||
log.Println("run sql request, sql is:", req.SQL)
|
||||
req.UserID = userID
|
||||
res, err2 := service.RunSQL(&req)
|
||||
if err2 != nil {
|
||||
resp.Code = proto.DBMRunSQLFailed
|
||||
resp.Message = "运行SQL失败: " + err2.Error()
|
||||
} else {
|
||||
resp.Code = proto.SuccessCode
|
||||
resp.Message = "运行SQL成功"
|
||||
resp.Data = res
|
||||
}
|
||||
}
|
||||
c.JSON(http.StatusOK, resp)
|
||||
return
|
||||
}
|
||||
|
||||
func GetDBTableDescHandler(c *gin.Context) {
|
||||
id, _ := c.Get("id")
|
||||
userID := int(id.(float64))
|
||||
|
||||
var req proto.GetDBTableDescReq
|
||||
var resp proto.GeneralResp
|
||||
if err := c.ShouldBind(&req); err != nil {
|
||||
resp.Code = proto.ParameterError
|
||||
resp.Message = "请求参数解析错误"
|
||||
} else {
|
||||
tableDesc, err2 := service.GetDBTableDesc(&req, userID)
|
||||
if err2 != nil {
|
||||
resp.Code = proto.DBMGetTableDescFailed
|
||||
resp.Message = "获取数据库表描述失败: " + err2.Error()
|
||||
} else {
|
||||
resp.Code = proto.SuccessCode
|
||||
resp.Message = "获取数据库表描述成功"
|
||||
resp.Data = tableDesc
|
||||
}
|
||||
}
|
||||
c.JSON(http.StatusOK, resp)
|
||||
}
|
||||
|
|
@ -1,10 +1,14 @@
|
|||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/google/uuid"
|
||||
"github.com/gorilla/websocket"
|
||||
"io"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
|
@ -58,7 +62,7 @@ func SetUpDeviceGroup(router *gin.Engine) {
|
|||
deviceGroup.POST("/update_device", UpdateDevice)
|
||||
deviceGroup.POST("/delete_device", DeleteDevice)
|
||||
deviceGroup.GET("/get_real_time_image", GetRealTimeImage)
|
||||
|
||||
deviceGroup.GET("/video_feed", VideoFeed)
|
||||
}
|
||||
|
||||
func DeleteDevice(c *gin.Context) {
|
||||
|
|
@ -206,71 +210,281 @@ func Restart(ip string) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
// 接收及发送消息
|
||||
// 发送实时视频流
|
||||
func GetRealTimeImage(c *gin.Context) {
|
||||
id, _ := c.Get("id")
|
||||
id1 := int(id.(float64))
|
||||
device_id := c.Query("device_id")
|
||||
//字符串转int
|
||||
device_id_int, _ := strconv.Atoi(device_id)
|
||||
device := service.GetDevice(device_id_int, id1)
|
||||
if device.ID == 0 {
|
||||
c.JSON(http.StatusOK, gin.H{"code": proto.DataNotFound, "message": "device not found"})
|
||||
return
|
||||
}
|
||||
//建立连接
|
||||
// 升级HTTP连接为WebSocket连接
|
||||
ws, err := upgrader.Upgrade(c.Writer, c.Request, nil)
|
||||
clients[ws] = true
|
||||
if err != nil {
|
||||
// log.Println(err)
|
||||
fmt.Println(err)
|
||||
fmt.Println("connect wss err:", err)
|
||||
return
|
||||
}
|
||||
worker.SetRedisWithExpire(strconv.Itoa(int(device.ID))+"_is_play", "1", time.Minute*5)
|
||||
fmt.Println("device_id:", device_id_int, " has set is_play to 1")
|
||||
go subscribeAndHandleMessagesV2(ws, device_id_int)
|
||||
}
|
||||
|
||||
func subscribeAndHandleMessagesV2(ws *websocket.Conn, device_id int) {
|
||||
ctx := context.Background()
|
||||
pubsub := worker.RedisClient.Subscribe(ctx, strconv.Itoa(device_id)+"_frames_msgs")
|
||||
// 生成唯一连接 uuid
|
||||
con_id := uuid.New().String()
|
||||
online_conn_key := "device_" + strconv.Itoa(device_id) + "_online_conn_ids"
|
||||
// 加入设备在线连接集合
|
||||
worker.SetRedisSetAddWithExpire(online_conn_key, con_id, time.Minute*5)
|
||||
defer pubsub.Close()
|
||||
defer ws.Close()
|
||||
worker.SetRedisWithExpire(strconv.Itoa(int(device.ID))+"_is_play", "1", time.Minute*5) //设置播放状态
|
||||
// 接收客户端消息并发送到指定用户
|
||||
|
||||
go func(ws *websocket.Conn, device_id int) {
|
||||
|
||||
}(ws, device_id_int)
|
||||
var check_cnt int
|
||||
|
||||
ch := pubsub.Channel()
|
||||
var ticker *time.Ticker // 定时器, 用于发送心跳包, 防止连接断开,每秒发送一次
|
||||
for {
|
||||
if v := clients[ws]; v == true {
|
||||
res2 := worker.PopRedisListLeft(device_id + "_frames")
|
||||
var res3 []byte
|
||||
var msg proto.Message
|
||||
if res2 != "" {
|
||||
//若有消息则发送消息
|
||||
msg.Type = "img"
|
||||
msg.Msg = res2
|
||||
msg.From_user_id = id1
|
||||
res3, _ = json.Marshal(msg)
|
||||
} else {
|
||||
//若无消息则发送心跳包
|
||||
if check_cnt < 5 {
|
||||
check_cnt++
|
||||
time.Sleep(time.Millisecond * 200) //设置延时200ms
|
||||
continue
|
||||
}
|
||||
check_cnt = 0
|
||||
msg.Type = "check"
|
||||
msg.Msg = "check"
|
||||
msg.From_user_id = -1
|
||||
res3, _ = json.Marshal(msg)
|
||||
select {
|
||||
case msg, _ := <-ch:
|
||||
frame := ""
|
||||
if msg.Payload != "" {
|
||||
frame = msg.Payload
|
||||
}
|
||||
err2 := ws.WriteMessage(websocket.TextMessage, res3)
|
||||
worker.SetRedisWithExpire(strconv.Itoa(int(device.ID))+"_is_play", "1", time.Minute*5) //设置播放状态
|
||||
//将base64图片数据解析为图片
|
||||
buf, err := base64.StdEncoding.DecodeString(frame)
|
||||
if err != nil {
|
||||
fmt.Println("base64 decode error:", err)
|
||||
continue
|
||||
}
|
||||
|
||||
err2 := ws.WriteMessage(websocket.BinaryMessage, buf)
|
||||
if err2 != nil {
|
||||
clientsMux.Lock()
|
||||
clients[ws] = false
|
||||
clientsMux.Unlock()
|
||||
//设置ws关闭状态信息
|
||||
worker.SetRedisWithExpire(strconv.Itoa(int(device.ID))+"_is_play", "0", time.Minute*5) //设置播放状态
|
||||
break
|
||||
fmt.Println("send message to client err:", err2)
|
||||
worker.SetRedisSetRemove(online_conn_key, con_id)
|
||||
goto end
|
||||
}
|
||||
default:
|
||||
if ticker == nil {
|
||||
ticker = time.NewTicker(time.Second)
|
||||
}
|
||||
select {
|
||||
case <-ticker.C:
|
||||
err := ws.WriteControl(websocket.PingMessage, []byte{}, time.Now().Add(time.Second))
|
||||
if err != nil {
|
||||
fmt.Println("Connection check failed:", err)
|
||||
worker.SetRedisSetRemove(online_conn_key, con_id)
|
||||
goto end
|
||||
}
|
||||
default:
|
||||
continue
|
||||
}
|
||||
time.Sleep(time.Millisecond * 200) //设置延时200ms
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
// 查看是否还有其他连接,没有则设置 is_play 为 0
|
||||
if worker.IsContainKey(online_conn_key) == false {
|
||||
worker.SetRedisWithExpire(strconv.Itoa(device_id)+"_is_play", "1", time.Minute*5)
|
||||
fmt.Println("device_id:", device_id, " has set is_play to 0")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func subscribeAndHandleMessages(ws *websocket.Conn, device_id int) {
|
||||
ctx := context.Background()
|
||||
pubsub := worker.RedisClient.Subscribe(ctx, strconv.Itoa(device_id)+"_frames_msgs")
|
||||
// 生成唯一连接 uuid
|
||||
con_id := uuid.New().String()
|
||||
online_conn_key := "device_" + strconv.Itoa(device_id) + "_online_conn_ids"
|
||||
// 加入设备在线连接集合
|
||||
worker.SetRedisSetAddWithExpire(online_conn_key, con_id, time.Minute*5)
|
||||
defer pubsub.Close()
|
||||
defer ws.Close()
|
||||
ch := pubsub.Channel()
|
||||
var check_cnt int
|
||||
var ticker *time.Ticker
|
||||
for {
|
||||
select {
|
||||
case msg, _ := <-ch:
|
||||
var res3 []byte
|
||||
var msgObj proto.Message
|
||||
if msg.Payload != "" {
|
||||
msgObj.Type = "img"
|
||||
msgObj.Msg = msg.Payload
|
||||
msgObj.From_user_id = -1
|
||||
res3, _ = json.Marshal(msgObj)
|
||||
} else {
|
||||
if check_cnt < 5 {
|
||||
check_cnt++
|
||||
time.Sleep(time.Millisecond * 200)
|
||||
continue
|
||||
}
|
||||
check_cnt = 0
|
||||
msgObj.Type = "check"
|
||||
msgObj.Msg = "check"
|
||||
msgObj.From_user_id = -1
|
||||
res3, _ = json.Marshal(msgObj)
|
||||
}
|
||||
// fmt.Println("send message to client length:", len(res3))
|
||||
err2 := ws.WriteMessage(websocket.TextMessage, res3)
|
||||
if err2 != nil {
|
||||
clientsMux.Lock()
|
||||
clients[ws] = false
|
||||
clientsMux.Unlock()
|
||||
fmt.Println("send message to client err:", err2)
|
||||
worker.SetRedisSetRemove(online_conn_key, con_id)
|
||||
goto end
|
||||
}
|
||||
default:
|
||||
if ticker == nil {
|
||||
ticker = time.NewTicker(time.Second)
|
||||
}
|
||||
select {
|
||||
case <-ticker.C:
|
||||
err := ws.WriteControl(websocket.PingMessage, []byte{}, time.Now().Add(time.Second))
|
||||
if err != nil {
|
||||
fmt.Println("Connection check failed:", err)
|
||||
worker.SetRedisSetRemove(online_conn_key, con_id)
|
||||
goto end
|
||||
}
|
||||
default:
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
// 查看是否还有其他连接,没有则设置 is_play 为 0
|
||||
if worker.IsContainKey(online_conn_key) == false {
|
||||
worker.SetRedisWithExpire(strconv.Itoa(device_id)+"_is_play", "0", time.Minute*5)
|
||||
fmt.Println("device_id:", device_id, " has set is_play to 0")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// VideoFeed 函数用于处理视频流的获取与返回,支持根据前端连接情况控制发送
|
||||
func VideoFeed(c *gin.Context) {
|
||||
// 更严谨地获取并转换 id 参数,处理可能的错误
|
||||
id, ok := c.Get("id")
|
||||
if !ok {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"code": proto.DataNotFound, "message": "id not found in context"})
|
||||
return
|
||||
}
|
||||
floatId, ok := id.(float64)
|
||||
if !ok {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"code": proto.DataFormatError, "message": "invalid id type in context"})
|
||||
return
|
||||
}
|
||||
user_id := int(floatId)
|
||||
|
||||
device_id := c.Query("device_id")
|
||||
device_id_int, err := strconv.Atoi(device_id)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"code": proto.DataFormatError, "message": "invalid device_id format"})
|
||||
return
|
||||
}
|
||||
|
||||
c.Header("Content-Type", "multipart/x-mixed-replace; boundary=frame") // 设置响应头
|
||||
|
||||
device := service.GetDevice(device_id_int, user_id)
|
||||
if device.ID == 0 {
|
||||
c.JSON(http.StatusOK, gin.H{"code": proto.DataNotFound, "message": "device not found"})
|
||||
return
|
||||
}
|
||||
|
||||
// 在 Redis 中设置设备正在播放状态及过期时间,处理设置失败的情况
|
||||
isSuccess := worker.SetRedisWithExpire(strconv.Itoa(int(device.ID))+"_is_play", "1", time.Minute*5)
|
||||
if isSuccess == false {
|
||||
fmt.Println("set redis is_play error:", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"code": proto.OperationFailed, "message": "failed to set device play status in Redis"})
|
||||
return
|
||||
}
|
||||
fmt.Println("device_id:", device_id_int, " has set is_play to 1")
|
||||
|
||||
ctx := context.Background()
|
||||
pubSub := worker.RedisClient.Subscribe(ctx, strconv.Itoa(device_id_int)+"_frames_msgs")
|
||||
|
||||
defer func() {
|
||||
err = pubSub.Close()
|
||||
if err != nil {
|
||||
fmt.Println("close pubSub error:", err)
|
||||
}
|
||||
}()
|
||||
|
||||
// 生成唯一连接 uuid
|
||||
//conId := uuid.New().String()
|
||||
//onlineConnKey := "device_" + strconv.Itoa(device_id_int) + "_online_conn_ids"
|
||||
//// 加入设备在线连接集合,处理添加失败的情况
|
||||
//worker.SetRedisSetAdd(onlineConnKey, conId)
|
||||
|
||||
// 创建一个通道用于接收客户端连接关闭的信号
|
||||
clientClosed := make(chan struct{})
|
||||
defer close(clientClosed)
|
||||
c.Stream(func(w io.Writer) bool {
|
||||
// 将读取 Redis 消息通道的逻辑放在这里,方便根据返回值控制循环
|
||||
ch := pubSub.Channel()
|
||||
for {
|
||||
select {
|
||||
case msg, ok := <-ch:
|
||||
if !ok {
|
||||
// 如果 Redis 通道关闭,进行相应处理并返回 false 停止发送
|
||||
fmt.Println("Redis channel closed unexpectedly")
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"code": proto.RedisSetError, "message": "Redis channel closed"})
|
||||
return false
|
||||
}
|
||||
// 将 base64 图片数据解析为图片
|
||||
frame := msg.Payload
|
||||
buf, err := base64.StdEncoding.DecodeString(frame)
|
||||
if err != nil {
|
||||
fmt.Println("base64 decode error:", err)
|
||||
continue
|
||||
}
|
||||
// 按照视频流格式要求构造并返回响应数据
|
||||
_, err = w.Write([]byte("--frame\r\n"))
|
||||
if err != nil {
|
||||
fmt.Println("write video frame error:", err)
|
||||
return false
|
||||
}
|
||||
_, err = w.Write([]byte("Content-Type: image/jpeg\r\n\r\n"))
|
||||
if err != nil {
|
||||
fmt.Println("write video frame error:", err)
|
||||
return false
|
||||
}
|
||||
_, err = w.Write(buf)
|
||||
if err != nil {
|
||||
fmt.Println("write video frame error:", err)
|
||||
return false
|
||||
}
|
||||
_, err = w.Write([]byte("\r\n"))
|
||||
if err != nil {
|
||||
fmt.Println("write video frame error:", err)
|
||||
return false
|
||||
}
|
||||
case <-clientClosed:
|
||||
// 当接收到客户端关闭连接的信号,返回 false 停止发送视频流
|
||||
return false
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// 启动一个协程来监测客户端连接是否关闭,关闭时向 clientClosed 通道发送信号
|
||||
go func() {
|
||||
<-c.Request.Context().Done()
|
||||
//如果clientClosed通道已经关闭,不再发送
|
||||
if _, ok := <-clientClosed; !ok {
|
||||
return
|
||||
} else {
|
||||
clientClosed <- struct{}{}
|
||||
}
|
||||
}()
|
||||
|
||||
// 查看是否还有其他连接,没有则设置 is_play 为 0
|
||||
//if worker.IsContainKey(onlineConnKey) == false {
|
||||
// worker.SetRedisWithExpire(strconv.Itoa(device_id_int)+"_is_play", "0", time.Minute*5)
|
||||
// fmt.Println("device_id:", device_id, " has set is_play to 0")
|
||||
//}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,194 @@
|
|||
package handler
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
"videoplayer/dao"
|
||||
"videoplayer/proto"
|
||||
"videoplayer/service"
|
||||
)
|
||||
|
||||
func SetUpFileGroup(router *gin.Engine) {
|
||||
fileGroup := router.Group("/file")
|
||||
fileGroup.POST("/config_add", AddConfigFile)
|
||||
fileGroup.POST("/config_delete", DeleteConfigFile)
|
||||
fileGroup.POST("/config_update", UpdateConfigFile)
|
||||
fileGroup.POST("/config_search", SearchConfigFile)
|
||||
fileGroup.POST("/upload", UploadFileV2)
|
||||
fileGroup.GET("/general/:filename", GetFile)
|
||||
|
||||
}
|
||||
|
||||
func AddConfigFile(c *gin.Context) {
|
||||
id, _ := c.Get("id")
|
||||
user_id := int(id.(float64))
|
||||
var req proto.AddConfigFileReq
|
||||
if err := c.ShouldBind(&req); err == nil {
|
||||
err2 := service.CreateConfigFile(&req, user_id)
|
||||
if err2 != nil {
|
||||
c.JSON(http.StatusOK, gin.H{"error": "add config file failed:" + err2.Error(), "code": proto.AddConfigFileFailed, "message": "failed"})
|
||||
return
|
||||
} else {
|
||||
c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "message": "success"})
|
||||
return
|
||||
}
|
||||
|
||||
} else {
|
||||
c.JSON(http.StatusOK, gin.H{"error": "upload form parameter decode error:" + err.Error(), "code": proto.ParameterError, "message": "failed"})
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func DeleteConfigFile(c *gin.Context) {
|
||||
id, _ := c.Get("id")
|
||||
user_id := int(id.(float64))
|
||||
var req proto.ConfigFileReq
|
||||
if err := c.ShouldBind(&req); err == nil {
|
||||
err2 := service.DeleteConfigFile(&req, user_id)
|
||||
if err2 != nil {
|
||||
c.JSON(http.StatusOK, gin.H{"error": "delete config file failed:" + err2.Error(), "code": proto.DeleteConfigFailed, "message": "failed"})
|
||||
return
|
||||
} else {
|
||||
c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "message": "success"})
|
||||
return
|
||||
}
|
||||
|
||||
} else {
|
||||
c.JSON(http.StatusOK, gin.H{"error": "upload form parameter decode error:" + err.Error(), "code": proto.ParameterError, "message": "failed"})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func UpdateConfigFile(c *gin.Context) {
|
||||
id, _ := c.Get("id")
|
||||
user_id := int(id.(float64))
|
||||
var req proto.ConfigFileReq
|
||||
if err := c.ShouldBind(&req); err == nil {
|
||||
var configFileService service.ConfigFileService
|
||||
err2 := configFileService.UpdateConfigFile(&req, user_id)
|
||||
if err2 != nil {
|
||||
c.JSON(http.StatusOK, gin.H{"error": "update config file failed:" + err2.Error(), "code": proto.UpdateConfigFailed, "message": "failed"})
|
||||
return
|
||||
} else {
|
||||
c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "message": "success"})
|
||||
return
|
||||
}
|
||||
|
||||
} else {
|
||||
c.JSON(http.StatusOK, gin.H{"error": "upload form parameter decode error:" + err.Error(), "code": proto.ParameterError, "message": "failed"})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func SearchConfigFile(c *gin.Context) {
|
||||
id, _ := c.Get("id")
|
||||
user_id := int(id.(float64))
|
||||
var req proto.ConfigFileReq
|
||||
if err := c.ShouldBind(&req); err == nil {
|
||||
var configFileService service.ConfigFileService
|
||||
if req.Type == "one" {
|
||||
//有文件内容
|
||||
configFile, err2 := configFileService.SearchOneConfigFile(&req, user_id)
|
||||
if err2 == nil {
|
||||
c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "msg": "success", "data": configFile})
|
||||
} else {
|
||||
c.JSON(http.StatusOK, gin.H{"code": proto.SearchConfigFileFailed, "msg": "info:" + err2.Error(), "data": configFile})
|
||||
}
|
||||
} else if req.Type == "all" {
|
||||
configFileList, err3 := configFileService.SearchAllConfigFile(user_id)
|
||||
if err3 == nil {
|
||||
c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "msg": "success", "data": configFileList})
|
||||
} else {
|
||||
c.JSON(http.StatusOK, gin.H{"code": proto.SearchConfigFileFailed, "msg": "info:" + err3.Error(), "data": configFileList})
|
||||
}
|
||||
} else {
|
||||
c.JSON(http.StatusOK, gin.H{"error": "search config file type error", "code": proto.ParameterError, "message": "failed"})
|
||||
}
|
||||
} else {
|
||||
c.JSON(http.StatusOK, gin.H{"error": "upload form parameter decode error:" + err.Error(), "code": proto.ParameterError, "message": "failed"})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func UploadFileV2(c *gin.Context) {
|
||||
//先查看是否有权限
|
||||
id, _ := c.Get("id")
|
||||
id1 := int(id.(float64))
|
||||
|
||||
var req proto.FileUploadReq
|
||||
//获取post form参数
|
||||
if err := c.ShouldBind(&req); err == nil {
|
||||
//检查参数
|
||||
if err2 := service.CheckUploadRequestParameters(&req); err2 != nil {
|
||||
c.JSON(http.StatusOK, gin.H{"error": "upload form parameter check error:" + err2.Error(), "code": proto.ParameterError, "message": "failed"})
|
||||
return
|
||||
}
|
||||
//
|
||||
|
||||
} else {
|
||||
c.JSON(http.StatusOK, gin.H{"error": "upload form parameter decode error:" + err.Error(), "code": proto.ParameterError, "message": "failed"})
|
||||
return
|
||||
}
|
||||
|
||||
//从请求头获取upload_type
|
||||
uploadType := c.PostForm("upload_type")
|
||||
authType := c.PostForm("auth_type")
|
||||
md5_ := c.PostForm("md5")
|
||||
if uploadType == "" {
|
||||
c.JSON(http.StatusOK, gin.H{"error": "upload_type is empty", "code": proto.ParameterError, "message": "failed"})
|
||||
return
|
||||
}
|
||||
|
||||
user := dao.FindUserByUserID(id1)
|
||||
if user.Upload <= 0 {
|
||||
c.JSON(http.StatusOK, gin.H{"error": "no upload Permissions", "code": proto.NoUploadPermissions, "message": "failed"})
|
||||
return
|
||||
}
|
||||
//上传文件
|
||||
file, err := c.FormFile("file")
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, gin.H{"error": "upload file failed", "code": proto.UploadFileFailed, "message": "failed"})
|
||||
return
|
||||
}
|
||||
//计算文件md5值
|
||||
if md5_ == "" {
|
||||
file_, _ := file.Open()
|
||||
md5_ = service.CalculateFileMd5(file_)
|
||||
if md5_ == "" {
|
||||
c.JSON(http.StatusOK, gin.H{"error": "计算文件MD5值失败", "code": proto.UploadFileFailed, "message": "failed"})
|
||||
return
|
||||
}
|
||||
}
|
||||
//查询文件是否已存在
|
||||
fileExist := dao.FindFileByMd5(md5_)
|
||||
if fileExist.ID != 0 {
|
||||
fileExist.FilePath = ""
|
||||
c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "message": "success", "data": fileExist})
|
||||
return
|
||||
}
|
||||
|
||||
//保存文件
|
||||
filePath, fileStoreName, err := service.SaveFile(c, file, uploadType)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, gin.H{"error": "save file failed", "code": proto.SaveFileFailed, "message": "failed"})
|
||||
return
|
||||
}
|
||||
//保存文件信息
|
||||
fileSize := int(file.Size)
|
||||
fileName := file.Filename
|
||||
fileType := file.Header.Get("file_type")
|
||||
var auth_type_ bool
|
||||
if authType == "public" || authType == "" {
|
||||
auth_type_ = false
|
||||
} else if authType == "private" {
|
||||
auth_type_ = true
|
||||
}
|
||||
file_record := dao.CreateFile(fileStoreName, fileName, fileType, filePath, md5_, fileSize, id1, auth_type_)
|
||||
if file_record.ID == 0 {
|
||||
c.JSON(http.StatusOK, gin.H{"error": "save file info failed", "code": proto.SaveFileInfoFailed, "message": "failed"})
|
||||
return
|
||||
}
|
||||
file_record.FilePath = ""
|
||||
c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "message": "success", "data": file_record})
|
||||
}
|
||||
202
handler/im.go
202
handler/im.go
|
|
@ -1,6 +1,7 @@
|
|||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
|
|
@ -35,6 +36,7 @@ type Message struct {
|
|||
}
|
||||
|
||||
type CGroup struct {
|
||||
ID int `json:"id" form:"id"`
|
||||
Group_name string `json:"group_name" form:"group_name"`
|
||||
Group_info string `json:"group_info" form:"group_info"`
|
||||
Group_type string `json:"group_type" form:"group_type"`
|
||||
|
|
@ -66,15 +68,19 @@ func SetUpIMGroup(router *gin.Engine) {
|
|||
imGroup.POST("/get_message", GetMessage)
|
||||
//接受邀请,确认好友关系
|
||||
imGroup.POST("/accept_invite", AcceptInvite)
|
||||
//拒绝邀请
|
||||
imGroup.POST("/reject_invite", RejectInvite)
|
||||
imGroup.POST("/create_group", CreateGroup)
|
||||
imGroup.POST("/update_group", UpdateGroup)
|
||||
imGroup.POST("/get_group", GetGroups)
|
||||
imGroup.POST("/get_group_req_user", GetFriendRequest)
|
||||
imGroup.GET("/sse_msg", ServerSendMsg)
|
||||
imGroup.GET("/ws_v2", ServerSsendMsgV2)
|
||||
imGroup.GET("/ws_v2", ServerSendMsgV3)
|
||||
imGroup.POST("/get_friend_list", GetFriendList) //获取好友列表,包括群聊
|
||||
//获取好友请求
|
||||
imGroup.POST("/get_friend_request", GetFriendRequest)
|
||||
imGroup.POST("/del_friend_or_group", DelFriendOrGroup)
|
||||
imGroup.POST("/get_group_users_info", GetGroupUsersInfo)
|
||||
}
|
||||
func generateRandomHexString(length int) (string, error) {
|
||||
bytes := make([]byte, length/2) // 16字节的字符串需要32个十六进制字符,即16个字节
|
||||
|
|
@ -84,6 +90,31 @@ func generateRandomHexString(length int) (string, error) {
|
|||
return hex.EncodeToString(bytes), nil
|
||||
}
|
||||
|
||||
func GetGroupUsersInfo(c *gin.Context) {
|
||||
var req Message
|
||||
id, _ := c.Get("id")
|
||||
user_id := int(id.(float64))
|
||||
if err := c.ShouldBind(&req); err == nil {
|
||||
if req.GroupID == 0 {
|
||||
c.JSON(http.StatusOK, gin.H{"error": "parameter error", "code": proto.ParameterError, "message": "failed"})
|
||||
return
|
||||
}
|
||||
group := dao.FindGroupByID(req.GroupID)
|
||||
if len(group) == 0 {
|
||||
c.JSON(http.StatusOK, gin.H{"error": "parameter error", "code": proto.ParameterError, "message": "failed"})
|
||||
return
|
||||
}
|
||||
if group[0].AuthID != user_id {
|
||||
c.JSON(http.StatusOK, gin.H{"error": "no permission", "code": proto.ParameterError, "message": "不是群主"})
|
||||
return
|
||||
}
|
||||
data := dao.FindGroupUsersInfo(req.GroupID)
|
||||
c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "data": data, "message": "success"})
|
||||
} else {
|
||||
c.JSON(http.StatusOK, gin.H{"error": err.Error(), "code": proto.ParameterError, "message": "failed"})
|
||||
}
|
||||
}
|
||||
|
||||
func GetGroups(c *gin.Context) {
|
||||
id, _ := c.Get("id")
|
||||
user_id := int(id.(float64))
|
||||
|
|
@ -92,6 +123,22 @@ func GetGroups(c *gin.Context) {
|
|||
|
||||
}
|
||||
|
||||
func UpdateGroup(c *gin.Context) {
|
||||
id, _ := c.Get("id")
|
||||
user_id := int(id.(float64))
|
||||
var req CGroup
|
||||
if err := c.ShouldBind(&req); err == nil {
|
||||
err2 := service.UpdateGroupService(req.ID, req.Group_name, req.Group_info, req.Group_type, req.Group_icon, user_id)
|
||||
if err2 == nil {
|
||||
c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "message": "success"})
|
||||
} else {
|
||||
c.JSON(http.StatusOK, gin.H{"error": err2.Error(), "code": proto.OperationFailed, "message": "failed"})
|
||||
}
|
||||
} else {
|
||||
c.JSON(http.StatusOK, gin.H{"error": err.Error(), "code": proto.ParameterError, "message": "failed"})
|
||||
}
|
||||
}
|
||||
|
||||
func DelFriendOrGroup(c *gin.Context) {
|
||||
var req Message
|
||||
user_id, _ := c.Get("id")
|
||||
|
|
@ -132,6 +179,29 @@ func DelFriendOrGroup(c *gin.Context) {
|
|||
} else {
|
||||
c.JSON(http.StatusOK, gin.H{"error": err2.Error(), "code": proto.OperationFailed, "message": "failed"})
|
||||
}
|
||||
} else if req.Type == 4 {
|
||||
//群管理员删除群成员
|
||||
if req.GroupID == 0 {
|
||||
c.JSON(http.StatusOK, gin.H{"error": "parameter error", "code": proto.ParameterError, "message": "failed,group_id is null"})
|
||||
return
|
||||
}
|
||||
//获取群
|
||||
group := dao.FindGroupByID(req.GroupID)
|
||||
if len(group) == 0 {
|
||||
c.JSON(http.StatusOK, gin.H{"error": "parameter error", "code": proto.ParameterError, "message": "failed group not found"})
|
||||
return
|
||||
}
|
||||
//判断是否是群主
|
||||
if group[0].AuthID != cid {
|
||||
c.JSON(http.StatusOK, gin.H{"error": "no permission", "code": proto.ParameterError, "message": "不是群主"})
|
||||
return
|
||||
}
|
||||
err2 := service.QuitGroupService(req.To_user_id, req.GroupID)
|
||||
if err2 == nil {
|
||||
c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "message": "success"})
|
||||
} else {
|
||||
c.JSON(http.StatusOK, gin.H{"error": err2.Error(), "code": proto.OperationFailed, "message": "failed"})
|
||||
}
|
||||
} else {
|
||||
c.JSON(http.StatusOK, gin.H{"error": "parameter error", "code": proto.ParameterError, "message": "failed"})
|
||||
}
|
||||
|
|
@ -152,7 +222,6 @@ func GetMessage(c *gin.Context) {
|
|||
id := int(user_id.(float64))
|
||||
//解析参数
|
||||
if err := c.ShouldBind(&req); err == nil {
|
||||
|
||||
if req.Type == 2 {
|
||||
msgs, err2 := dao.GetMsgGroupByIndex(req.GroupID, req.Index)
|
||||
if err2 == nil {
|
||||
|
|
@ -215,11 +284,52 @@ func AcceptInvite(c *gin.Context) {
|
|||
user_id, _ := c.Get("id")
|
||||
cid := int(user_id.(float64))
|
||||
if err := c.ShouldBind(&req); err == nil {
|
||||
err2 := service.AddFriendService(req.ID, cid, req.To_user_id)
|
||||
if err2 == nil {
|
||||
c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "message": "success"})
|
||||
if req.Type == 1 {
|
||||
//同意添加好友
|
||||
err2 := service.AddFriendService(req.ID, cid, req.To_user_id)
|
||||
if err2 == nil {
|
||||
c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "message": "success"})
|
||||
} else {
|
||||
c.JSON(http.StatusOK, gin.H{"error": err2.Error(), "code": proto.OperationFailed, "message": "failed"})
|
||||
}
|
||||
} else if req.Type == 2 {
|
||||
//同意加入群聊
|
||||
err3 := service.JoinGroupService(req.ID, cid, req.To_user_id, req.GroupID)
|
||||
if err3 == nil {
|
||||
c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "message": "success"})
|
||||
} else {
|
||||
c.JSON(http.StatusOK, gin.H{"error": err3.Error(), "code": proto.OperationFailed, "message": "failed"})
|
||||
}
|
||||
} else {
|
||||
c.JSON(http.StatusOK, gin.H{"error": err2.Error(), "code": proto.OperationFailed, "message": "failed"})
|
||||
c.JSON(http.StatusOK, gin.H{"error": err.Error(), "code": proto.ParameterError, "message": "failed"})
|
||||
}
|
||||
} else {
|
||||
c.JSON(http.StatusOK, gin.H{"error": err.Error(), "code": proto.ParameterError, "message": "failed"})
|
||||
}
|
||||
}
|
||||
func RejectInvite(c *gin.Context) {
|
||||
var req Message
|
||||
user_id, _ := c.Get("id")
|
||||
cid := int(user_id.(float64))
|
||||
if err := c.ShouldBind(&req); err == nil {
|
||||
if req.Type == 1 {
|
||||
//拒绝添加好友
|
||||
err2 := service.RejectFriendService(req.ID, cid, req.To_user_id)
|
||||
if err2 == nil {
|
||||
c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "message": "success"})
|
||||
} else {
|
||||
c.JSON(http.StatusOK, gin.H{"error": err2.Error(), "code": proto.OperationFailed, "message": "failed"})
|
||||
}
|
||||
} else if req.Type == 2 {
|
||||
//拒绝加入群聊
|
||||
err3 := service.RejectGroupService(req.ID, cid, req.To_user_id, req.GroupID)
|
||||
if err3 == nil {
|
||||
c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "message": "success"})
|
||||
} else {
|
||||
c.JSON(http.StatusOK, gin.H{"error": err3.Error(), "code": proto.OperationFailed, "message": "failed"})
|
||||
}
|
||||
} else {
|
||||
c.JSON(http.StatusOK, gin.H{"error": "parameter error", "code": proto.ParameterError, "message": "failed type error"})
|
||||
}
|
||||
} else {
|
||||
c.JSON(http.StatusOK, gin.H{"error": err.Error(), "code": proto.ParameterError, "message": "failed"})
|
||||
|
|
@ -432,7 +542,7 @@ func SRMessage(c *gin.Context) {
|
|||
}
|
||||
}
|
||||
|
||||
func ServerSsendMsgV2(c *gin.Context) {
|
||||
func ServerSendMsgV2(c *gin.Context) {
|
||||
//wss
|
||||
id, _ := c.Get("id")
|
||||
user_id := int(id.(float64))
|
||||
|
|
@ -448,8 +558,9 @@ func ServerSsendMsgV2(c *gin.Context) {
|
|||
defer ws.Close()
|
||||
//设置用户在线状态
|
||||
worker.SetRedisWithExpire("user_"+strconv.Itoa(user_id)+"_status_v2", "1", time.Second*60)
|
||||
worker.SetRedisBitmap("im2_online_users", int64(user_id), 1)
|
||||
worker.SetRedisSetAdd("im2_online_users_set", strconv.Itoa(user_id))
|
||||
//发送消息
|
||||
|
||||
key := "user_" + strconv.Itoa(user_id) + "_msg_ids"
|
||||
|
||||
for {
|
||||
|
|
@ -485,6 +596,8 @@ func ServerSsendMsgV2(c *gin.Context) {
|
|||
err2 := ws.WriteMessage(websocket.TextMessage, res3)
|
||||
if err2 != nil {
|
||||
worker.SetRedisWithExpire("user_"+strconv.Itoa(user_id)+"_status_v2", "0", time.Second*3600)
|
||||
worker.SetRedisBitmap("im2_online_users", int64(user_id), 0)
|
||||
worker.SetRedisSetRemove("im2_online_users_set", strconv.Itoa(user_id))
|
||||
clientsMux.Lock()
|
||||
delete(clients, ws)
|
||||
clientsMux.Unlock()
|
||||
|
|
@ -495,6 +608,28 @@ func ServerSsendMsgV2(c *gin.Context) {
|
|||
time.Sleep(time.Second * 1)
|
||||
}
|
||||
}
|
||||
|
||||
func ServerSendMsgV3(c *gin.Context) {
|
||||
//ws
|
||||
id, _ := c.Get("id")
|
||||
user_id := int(id.(float64))
|
||||
|
||||
// 升级HTTP连接为WebSocket连接
|
||||
ws, err1 := upgrader.Upgrade(c.Writer, c.Request, nil)
|
||||
clients[ws] = true
|
||||
if err1 != nil {
|
||||
// log.Println(err)
|
||||
fmt.Println(err1)
|
||||
return
|
||||
}
|
||||
//设置用户在线状态
|
||||
worker.SetRedisWithExpire("user_"+strconv.Itoa(user_id)+"_status_v2", "1", time.Second*60)
|
||||
worker.SetRedisBitmap("im2_online_users", int64(user_id), 1)
|
||||
worker.SetRedisSetAdd("im2_online_users_set", strconv.Itoa(user_id))
|
||||
//发送消息
|
||||
key := "user_" + strconv.Itoa(user_id) + "_msg_ids"
|
||||
go subscribeAndHandleIMMessages(ws, key, user_id)
|
||||
}
|
||||
func ServerSendMsg(c *gin.Context) {
|
||||
//sse
|
||||
c.Writer.Header().Set("Content-Type", "text/event-stream")
|
||||
|
|
@ -542,3 +677,54 @@ func ServerSendMsg(c *gin.Context) {
|
|||
time.Sleep(time.Second * 1)
|
||||
}
|
||||
}
|
||||
|
||||
func subscribeAndHandleIMMessages(ws *websocket.Conn, chanel string, user_id int) {
|
||||
ctx := context.Background()
|
||||
pubsub := worker.RedisClient.Subscribe(ctx, chanel)
|
||||
defer pubsub.Close()
|
||||
defer ws.Close()
|
||||
ch := pubsub.Channel()
|
||||
for m := range ch {
|
||||
msg_id := m.Payload //消息id
|
||||
if msg_id != "" {
|
||||
msg_id_num, _ := strconv.ParseInt(msg_id, 10, 64)
|
||||
msgs := dao.FindMessageByID2(uint(msg_id_num))
|
||||
if len(msgs) > 0 {
|
||||
msg := msgs[0]
|
||||
//发送消息
|
||||
msg_str, _ := json.Marshal(msg)
|
||||
var msg_ proto.Message
|
||||
msg_.Type = "msg"
|
||||
msg_.Msg = string(msg_str)
|
||||
msg_str2, _ := json.Marshal(msg_)
|
||||
|
||||
err2 := ws.WriteMessage(websocket.TextMessage, msg_str2)
|
||||
if err2 != nil {
|
||||
worker.SetRedisWithExpire("user_"+strconv.Itoa(user_id)+"_status_v2", "0", time.Second*3600)
|
||||
clientsMux.Lock()
|
||||
delete(clients, ws)
|
||||
clientsMux.Unlock()
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var msg proto.Message
|
||||
msg.Type = "check"
|
||||
msg.Msg = "check"
|
||||
msg.From_user_id = -1
|
||||
//发送心跳包
|
||||
res3, _ := json.Marshal(msg)
|
||||
err2 := ws.WriteMessage(websocket.TextMessage, res3)
|
||||
if err2 != nil {
|
||||
worker.SetRedisWithExpire("user_"+strconv.Itoa(user_id)+"_status_v2", "0", time.Second*3600)
|
||||
worker.SetRedisBitmap("im2_online_users", int64(user_id), 0)
|
||||
worker.SetRedisSetRemove("im2_online_users_set", strconv.Itoa(user_id))
|
||||
clientsMux.Lock()
|
||||
delete(clients, ws)
|
||||
clientsMux.Unlock()
|
||||
break
|
||||
}
|
||||
}
|
||||
worker.SetRedisWithExpire("user_"+strconv.Itoa(user_id)+"_status_v2", "1", time.Second*60)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,152 @@
|
|||
package handler
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
"videoplayer/proto"
|
||||
"videoplayer/service"
|
||||
)
|
||||
|
||||
type ShellHandler struct {
|
||||
}
|
||||
|
||||
type CreateShellReq struct {
|
||||
ShellName string `json:"shell_name" form:"shell_name" binding:"required"`
|
||||
ShellContent string `json:"shell_content" form:"shell_content" binding:"required"`
|
||||
Server string `json:"server" form:"server" binding:"required"`
|
||||
}
|
||||
type UpdateShellReq struct {
|
||||
ID uint `json:"id" form:"id" binding:"required"`
|
||||
ShellName string `json:"shell_name" form:"shell_name"`
|
||||
ShellContent string `json:"shell_content" form:"shell_content"`
|
||||
Server string `json:"server" form:"server"`
|
||||
Status int `json:"status" form:"status"`
|
||||
ShellResult string `json:"shell_result" form:"shell_result"`
|
||||
ShellRuntime float64 `json:"shell_runtime" form:"shell_runtime"` // 执行时间,单位秒
|
||||
ShellDuration float64 `json:"shell_duration" form:"shell_duration"` // 执行时长,单位秒
|
||||
}
|
||||
|
||||
type UpdateShellReqV2 struct {
|
||||
Shells []UpdateShellReq `json:"shells" form:"shells"`
|
||||
}
|
||||
|
||||
type UpdateShellResp struct {
|
||||
ID uint `json:"id" form:"id"`
|
||||
Status int `json:"status" form:"status"`
|
||||
}
|
||||
|
||||
type DeleteShellRequestID struct {
|
||||
ID uint `json:"id" form:"id" binding:"required"`
|
||||
}
|
||||
type DeleteShellRequest struct {
|
||||
Shells []DeleteShellRequestID `json:"shells" form:"shells" binding:"required"`
|
||||
}
|
||||
|
||||
func SetUpShellGroup(router *gin.Engine) {
|
||||
shellGroup := router.Group("/shell") //持续集成、部署
|
||||
shellHandler := ShellHandler{}
|
||||
shellGroup.POST("/create", shellHandler.CreateShell)
|
||||
shellGroup.POST("/list", shellHandler.ListShell)
|
||||
shellGroup.POST("/update", shellHandler.UpdateShell)
|
||||
shellGroup.POST("/delete", shellHandler.DeleteShell)
|
||||
shellGroup.POST("/server_will_run_list", shellHandler.ServerWillRun)
|
||||
}
|
||||
|
||||
func (s *ShellHandler) CreateShell(c *gin.Context) {
|
||||
user_id, _ := c.Get("id")
|
||||
uid := int(user_id.(float64))
|
||||
var req CreateShellReq
|
||||
if err := c.ShouldBind(&req); err != nil {
|
||||
c.JSON(200, gin.H{"code": proto.ShellCreateFailed, "message": "参数错误", "data": err.Error()})
|
||||
} else {
|
||||
id := service.CreateShell(req.ShellName, req.ShellContent, req.Server, uid)
|
||||
if id == 0 {
|
||||
c.JSON(200, gin.H{"code": proto.ShellCreateFailed, "message": "创建失败,id is 0", "data": ""})
|
||||
return
|
||||
}
|
||||
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "创建成功", "data": id})
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ShellHandler) ListShell(c *gin.Context) {
|
||||
userId, _ := c.Get("id")
|
||||
id := int(userId.(float64))
|
||||
shells := service.FindShellByAuthID(id)
|
||||
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "获取成功", "data": shells})
|
||||
}
|
||||
|
||||
func (s *ShellHandler) UpdateShell(c *gin.Context) {
|
||||
var req UpdateShellReqV2
|
||||
userId, _ := c.Get("id")
|
||||
id := int(userId.(float64))
|
||||
if err := c.ShouldBind(&req); err != nil {
|
||||
c.JSON(200, gin.H{"code": proto.ShellUpdateFailed, "message": "参数错误", "data": err.Error()})
|
||||
} else {
|
||||
var resp []UpdateShellResp
|
||||
//log.Println("UpdateShellReqData:", req.Shells)
|
||||
for _, v := range req.Shells {
|
||||
if service.UpdateShellByIDV2(v.ID, uint(id), v.ShellName, v.ShellContent, v.Server, v.Status, v.ShellResult, v.ShellRuntime) {
|
||||
resp = append(resp, UpdateShellResp{ID: v.ID, Status: v.Status})
|
||||
} else {
|
||||
resp = append(resp, UpdateShellResp{ID: v.ID, Status: -1})
|
||||
}
|
||||
}
|
||||
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "更新成功", "data": resp})
|
||||
}
|
||||
}
|
||||
|
||||
type DeleteShellResp struct {
|
||||
Success []DeleteShellRequestID `json:"success" form:"success"`
|
||||
Error []DeleteShellRequestID `json:"error" form:"error"`
|
||||
}
|
||||
|
||||
func (s *ShellHandler) DeleteShell(c *gin.Context) {
|
||||
userId, _ := c.Get("id")
|
||||
id := int(userId.(float64))
|
||||
var req DeleteShellRequest
|
||||
var resp proto.GeneralResp
|
||||
|
||||
if err := c.ShouldBind(&req); err == nil {
|
||||
var delSuccessIDs []DeleteShellRequestID
|
||||
var delErrorIDs []DeleteShellRequestID
|
||||
for _, v := range req.Shells {
|
||||
delSuccess := service.DeleteShellByID(v.ID, uint(id))
|
||||
if delSuccess {
|
||||
delSuccessIDs = append(delSuccessIDs, v)
|
||||
} else {
|
||||
delErrorIDs = append(delErrorIDs, v)
|
||||
}
|
||||
}
|
||||
var delResp DeleteShellResp
|
||||
delResp.Success = delSuccessIDs
|
||||
delResp.Error = delErrorIDs
|
||||
resp.Code = proto.SuccessCode
|
||||
resp.Data = delResp
|
||||
resp.Message = "success"
|
||||
} else {
|
||||
resp.Code = proto.ParameterError
|
||||
resp.Message = "参数解析错误:" + err.Error()
|
||||
}
|
||||
c.JSON(http.StatusOK, resp)
|
||||
}
|
||||
|
||||
type ServerWillRunReq struct {
|
||||
Server string `json:"server"`
|
||||
}
|
||||
|
||||
func (s *ShellHandler) ServerWillRun(c *gin.Context) {
|
||||
userId, _ := c.Get("id")
|
||||
id := int(userId.(float64))
|
||||
var req ServerWillRunReq
|
||||
if err := c.ShouldBind(&req); err != nil {
|
||||
c.JSON(200, gin.H{"code": proto.ShellUpdateFailed, "message": "参数错误", "data": err.Error()})
|
||||
} else {
|
||||
//log.Printf("ServerWillRunReq:%s,id:%d", req.Server, id)
|
||||
willRunShells, err2 := service.FindShellWillRunByServer(req.Server, id)
|
||||
if err2 != nil {
|
||||
c.JSON(200, gin.H{"code": proto.ShellUpdateFailed, "message": "获取失败", "data": err2.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "获取成功", "data": willRunShells})
|
||||
}
|
||||
}
|
||||
392
handler/tool.go
392
handler/tool.go
|
|
@ -4,12 +4,17 @@ import (
|
|||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"time"
|
||||
"videoplayer/dao"
|
||||
"videoplayer/proto"
|
||||
"videoplayer/service"
|
||||
"videoplayer/worker"
|
||||
)
|
||||
|
||||
type SetRedisReq struct {
|
||||
|
|
@ -19,6 +24,22 @@ type SetRedisReq struct {
|
|||
Expire int `json:"expire" form:"expire"`
|
||||
}
|
||||
|
||||
type SetDeviceStatusReq struct {
|
||||
ID string `json:"id" form:"id"` //设备编码
|
||||
Status string `json:"status" form:"status"` //设备状态
|
||||
}
|
||||
|
||||
type GetFileListReq struct {
|
||||
Type string `json:"type" form:"type"` //请求类型,1:按md5查询,2:按文件名查询;3:查询待删除文件
|
||||
Md5 string `json:"md5" form:"md5"`
|
||||
}
|
||||
|
||||
type SendMailReq struct {
|
||||
Title string `json:"title" form:"title"`
|
||||
Content string `json:"content" form:"content"`
|
||||
To string `json:"to" form:"to"`
|
||||
}
|
||||
|
||||
func SetUpToolGroup(router *gin.Engine) {
|
||||
toolGroup := router.Group("/tool")
|
||||
toolGroup.POST("/set_redis", SetRedis)
|
||||
|
|
@ -27,8 +48,152 @@ func SetUpToolGroup(router *gin.Engine) {
|
|||
//文件上传、下载
|
||||
toolGroup.POST("/upload", UploadFile)
|
||||
toolGroup.GET("/download", DownloadFile)
|
||||
toolGroup.GET("/file/:filename", GetFile)
|
||||
toolGroup.POST("/file_list", GetFileList)
|
||||
//文件管理
|
||||
toolGroup.POST("/file_del", DelFile)
|
||||
//服务器、设备状态接口
|
||||
toolGroup.POST("/monitor", SetDeviceStatusV2)
|
||||
toolGroup.GET("/get_monitor_list", GetMonitorList) //获取设备监控列表
|
||||
toolGroup.POST("/update_monitor", UpdateMonitor) //设置设备状态
|
||||
toolGroup.POST("/del_monitor", DelMonitor) //删除设备监控
|
||||
//发送邮件
|
||||
toolGroup.POST("/send_mail", SendMailTool)
|
||||
//下载代理
|
||||
toolGroup.GET("/dlp", DownloadProxyHandle)
|
||||
}
|
||||
|
||||
func GetMonitorList(c *gin.Context) {
|
||||
id, _ := c.Get("id")
|
||||
userId := int(id.(float64))
|
||||
var resp proto.GeneralResp
|
||||
monitorDeviceList, err := service.GetMonitorDeviceListWithStatus(userId)
|
||||
if err != nil {
|
||||
resp.Code = proto.OperationFailed
|
||||
resp.Message = err.Error()
|
||||
} else {
|
||||
resp.Code = proto.SuccessCode
|
||||
resp.Message = "success"
|
||||
resp.Data = monitorDeviceList
|
||||
}
|
||||
c.JSON(http.StatusOK, resp)
|
||||
}
|
||||
|
||||
type UpdateMonitorDeviceStatusReq struct {
|
||||
Devices []proto.GetMonitorDeviceStatus `json:"devices" form:"devices"` //设备状态列表
|
||||
}
|
||||
|
||||
func UpdateMonitor(c *gin.Context) {
|
||||
id, _ := c.Get("id")
|
||||
id1 := int(id.(float64))
|
||||
var req UpdateMonitorDeviceStatusReq
|
||||
var resp proto.GeneralResp
|
||||
if err := c.ShouldBind(&req); err == nil {
|
||||
err2 := service.UpdateMonitorDeviceListWithStatus(id1, req.Devices)
|
||||
if err2 != nil {
|
||||
resp.Code = proto.OperationFailed
|
||||
resp.Message = "更新设备状态失败:" + err2.Error()
|
||||
} else {
|
||||
resp.Code = proto.SuccessCode
|
||||
resp.Message = "更新设备状态成功"
|
||||
}
|
||||
} else {
|
||||
resp.Code = proto.ParameterError
|
||||
resp.Message = "参数解析失败:" + err.Error()
|
||||
}
|
||||
c.JSON(http.StatusOK, resp)
|
||||
}
|
||||
func DelMonitor(c *gin.Context) {
|
||||
id, _ := c.Get("id")
|
||||
id1 := int(id.(float64))
|
||||
var req UpdateMonitorDeviceStatusReq
|
||||
var resp proto.GeneralResp
|
||||
if err := c.ShouldBind(&req); err == nil {
|
||||
delSuccess, err2 := service.DelMonitorDeviceListWithStatus(id1, req.Devices)
|
||||
if err2 != nil {
|
||||
resp.Code = proto.OperationFailed
|
||||
resp.Message = "更新设备状态失败:" + err2.Error()
|
||||
resp.Data = delSuccess
|
||||
} else {
|
||||
resp.Code = proto.SuccessCode
|
||||
resp.Message = "更新设备状态成功"
|
||||
resp.Data = delSuccess
|
||||
}
|
||||
} else {
|
||||
resp.Code = proto.ParameterError
|
||||
resp.Message = "参数解析失败:" + err.Error()
|
||||
}
|
||||
c.JSON(http.StatusOK, resp)
|
||||
}
|
||||
|
||||
func SetDeviceStatusV2(c *gin.Context) {
|
||||
// TODO
|
||||
var req SetDeviceStatusReq
|
||||
var resp proto.GeneralResp
|
||||
if err := c.ShouldBind(&req); err != nil {
|
||||
resp.Code = proto.ParameterError
|
||||
resp.Message = "参数解析失败:" + err.Error()
|
||||
} else {
|
||||
token := c.Request.Header.Get("token")
|
||||
if token == "" {
|
||||
resp.Code = proto.TokenIsNull //token为空
|
||||
} else {
|
||||
devices := worker.GetRedisSetMembers(token)
|
||||
if len(devices) == 0 {
|
||||
resp.Code = proto.MonitorServerIDIsNull
|
||||
resp.Message = "服务器设备监控为空!"
|
||||
} else {
|
||||
isExit := false
|
||||
for _, v := range devices {
|
||||
if v == req.ID {
|
||||
// 继续处理请求
|
||||
//是否是暂停之后第一次上线,如果是则发送邮件通知
|
||||
deviceStatus := worker.GetRedis("monitor_" + req.ID)
|
||||
isExist := worker.IsContainKey("monitor_" + req.ID)
|
||||
if deviceStatus == "2" || !isExist {
|
||||
//发送邮件通知
|
||||
title := "设备上线"
|
||||
content := "设备上线\n设备:" + req.ID + "\t状态:" + req.Status + "\t时间:" + time.Now().String()
|
||||
go SendMail(title, content)
|
||||
}
|
||||
worker.SetRedisWithExpire("monitor_"+req.ID, "1", time.Second*300)
|
||||
resp.Code = proto.SuccessCode
|
||||
resp.Message = "success"
|
||||
isExit = true
|
||||
}
|
||||
}
|
||||
if isExit == false {
|
||||
resp.Code = proto.MonitorServerIDNotFound
|
||||
resp.Message = "设备不存在!"
|
||||
log.Println("设备不存在,id:", req.ID, "\ttoken:", token, "\tdevices:", devices)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
c.JSON(http.StatusOK, resp)
|
||||
}
|
||||
|
||||
func GetFileList(c *gin.Context) {
|
||||
//解析请求参数
|
||||
var req GetFileListReq
|
||||
if err := c.ShouldBind(&req); err == nil {
|
||||
if req.Type == "1" {
|
||||
//按md5查询
|
||||
if req.Md5 == "" {
|
||||
c.JSON(http.StatusOK, gin.H{"error": "md5 is empty", "code": proto.ParameterError, "message": "failed"})
|
||||
return
|
||||
}
|
||||
file := dao.FindFileByMd5(req.Md5)
|
||||
if file.ID == 0 {
|
||||
c.JSON(http.StatusOK, gin.H{"error": "file not found", "code": proto.FileNotFound, "message": "failed"})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "message": "success", "data": file})
|
||||
}
|
||||
} else {
|
||||
c.JSON(http.StatusOK, gin.H{"error": "parameter error", "code": proto.ParameterError, "message": "failed"})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func DelFile(c *gin.Context) {
|
||||
|
|
@ -58,19 +223,42 @@ func DelFile(c *gin.Context) {
|
|||
|
||||
}
|
||||
|
||||
func GetFile(c *gin.Context) {
|
||||
//先查看是否有权限
|
||||
filename := c.Param("filename")
|
||||
if filename == "" {
|
||||
c.JSON(http.StatusOK, gin.H{"error": "filename is empty", "code": proto.ParameterError, "message": "failed"})
|
||||
return
|
||||
}
|
||||
//查询文件信息
|
||||
file := dao.FindFileByName(filename)
|
||||
if file.ID == 0 {
|
||||
c.JSON(http.StatusOK, gin.H{"error": "file not found", "code": proto.FileNotFound, "message": "failed"})
|
||||
return
|
||||
}
|
||||
//下载文件
|
||||
if file.NeedAuth == false {
|
||||
c.File(file.FilePath + "/" + file.FileStoreName)
|
||||
} else {
|
||||
c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "message": "file must auth", "data": "file must auth"})
|
||||
}
|
||||
}
|
||||
|
||||
func UploadFile(c *gin.Context) {
|
||||
//先查看是否有权限
|
||||
id, _ := c.Get("id")
|
||||
id1 := int(id.(float64))
|
||||
//从请求头获取upload_type
|
||||
uploadType := c.PostForm("upload_type")
|
||||
authType := c.PostForm("auth_type")
|
||||
md5_ := c.PostForm("md5")
|
||||
if uploadType == "" {
|
||||
c.JSON(http.StatusOK, gin.H{"error": "upload_type is empty", "code": proto.ParameterError, "message": "failed"})
|
||||
return
|
||||
}
|
||||
|
||||
user := dao.FindUserByUserID(id1)
|
||||
if user.Upload == false {
|
||||
if user.Upload <= 0 {
|
||||
c.JSON(http.StatusOK, gin.H{"error": "no upload Permissions", "code": proto.NoUploadPermissions, "message": "failed"})
|
||||
return
|
||||
}
|
||||
|
|
@ -80,6 +268,22 @@ func UploadFile(c *gin.Context) {
|
|||
c.JSON(http.StatusOK, gin.H{"error": "upload file failed", "code": proto.UploadFileFailed, "message": "failed"})
|
||||
return
|
||||
}
|
||||
//计算文件md5值
|
||||
if md5_ == "" {
|
||||
file_, _ := file.Open()
|
||||
md5_ = service.CalculateFileMd5(file_)
|
||||
if md5_ == "" {
|
||||
c.JSON(http.StatusOK, gin.H{"error": "计算文件MD5值失败", "code": proto.UploadFileFailed, "message": "failed"})
|
||||
return
|
||||
}
|
||||
}
|
||||
//查询文件是否已存在
|
||||
fileExist := dao.FindFileByMd5(md5_)
|
||||
if fileExist.ID != 0 {
|
||||
fileExist.FilePath = ""
|
||||
c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "message": "success", "data": fileExist})
|
||||
return
|
||||
}
|
||||
|
||||
//保存文件
|
||||
filePath, fileStoreName, err := service.SaveFile(c, file, uploadType)
|
||||
|
|
@ -91,12 +295,19 @@ func UploadFile(c *gin.Context) {
|
|||
fileSize := int(file.Size)
|
||||
fileName := file.Filename
|
||||
fileType := file.Header.Get("file_type")
|
||||
fileID := dao.CreateFile(fileStoreName, fileName, fileType, filePath, fileSize, id1)
|
||||
if fileID == 0 {
|
||||
var auth_type_ bool
|
||||
if authType == "public" || authType == "" {
|
||||
auth_type_ = false
|
||||
} else if authType == "private" {
|
||||
auth_type_ = true
|
||||
}
|
||||
file_record := dao.CreateFile(fileStoreName, fileName, fileType, filePath, md5_, fileSize, id1, auth_type_)
|
||||
if file_record.ID == 0 {
|
||||
c.JSON(http.StatusOK, gin.H{"error": "save file info failed", "code": proto.SaveFileInfoFailed, "message": "failed"})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "message": "success", "data": fileID})
|
||||
file_record.FilePath = ""
|
||||
c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "message": "success", "data": file_record})
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -140,7 +351,7 @@ func SetRedis(c *gin.Context) {
|
|||
id, _ := c.Get("id")
|
||||
id1 := int(id.(float64))
|
||||
user := dao.FindUserByUserID(id1)
|
||||
if user.Redis == false {
|
||||
if user.Redis <= 0 {
|
||||
c.JSON(http.StatusOK, gin.H{"error": "no redis Permissions", "code": proto.NoRedisPermissions, "message": "failed"})
|
||||
return
|
||||
}
|
||||
|
|
@ -168,18 +379,181 @@ func GetRedis(c *gin.Context) {
|
|||
id, _ := c.Get("id")
|
||||
id1 := int(id.(float64))
|
||||
user := dao.FindUserByUserID(id1)
|
||||
if user.Redis == false {
|
||||
if user.Redis <= 0 {
|
||||
c.JSON(http.StatusOK, gin.H{"error": "no redis Permissions", "code": proto.NoRedisPermissions, "message": "failed"})
|
||||
return
|
||||
}
|
||||
//解析请求参数
|
||||
var req SetRedisReq
|
||||
if err := c.ShouldBind(&req); err == nil {
|
||||
code, message := service.GetToolRedis(req.Key)
|
||||
req.Value = message
|
||||
c.JSON(http.StatusOK, gin.H{"code": code, "message": message, "data": req})
|
||||
if req.Option == "one" {
|
||||
code, message := service.GetToolRedis(req.Key)
|
||||
req.Value = message
|
||||
c.JSON(http.StatusOK, gin.H{"code": code, "message": message, "data": req})
|
||||
} else if req.Option == "all" {
|
||||
code, message, data := service.GetAllRedis()
|
||||
c.JSON(http.StatusOK, gin.H{"code": code, "message": message, "data": data})
|
||||
}
|
||||
} else {
|
||||
c.JSON(http.StatusOK, gin.H{"error": "parameter error", "code": proto.ParameterError, "message": "failed"})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 服务器、设备状态扫描
|
||||
func ScanDeviceStatus() {
|
||||
// TODO
|
||||
// 检查设备状态
|
||||
// 如果设备状态异常, 则发送邮件通知
|
||||
devices := worker.GetRedisSetMembers("627gyf3488h")
|
||||
offline := ""
|
||||
for _, v := range devices {
|
||||
c := worker.IsContainKey("monitor_" + v)
|
||||
if c == false {
|
||||
worker.SetRedisWithExpire("monitor_"+v, "2", time.Hour*24)
|
||||
offline += v + ","
|
||||
}
|
||||
}
|
||||
|
||||
if offline != "" {
|
||||
title := "设备状态异常"
|
||||
content := "设备状态异常\n设备: " + offline + "\t时间:" + time.Now().String()
|
||||
go SendMail(title, content)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func SendMail(title, content string) {
|
||||
//捕获异常
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
fmt.Errorf("tool send mail error: %s", err)
|
||||
}
|
||||
}()
|
||||
// TODO
|
||||
// 发送邮件
|
||||
// 邮件内容
|
||||
// 邮件标题
|
||||
// 收件人
|
||||
// 发送邮件
|
||||
// 发送邮件通知
|
||||
// 发送邮件通知
|
||||
var em worker.MyEmail
|
||||
em.SmtpPassword = "nihzazdkmucnbhid"
|
||||
em.SmtpHost = "pop.qq.com:587"
|
||||
em.SmtpUserName = "354425203@qq.com"
|
||||
em.SmtpPort = 587
|
||||
em.ImapPort = 993
|
||||
var targetMails []string
|
||||
for _, v := range proto.Config.MONITOR_MAIL {
|
||||
targetMails = append(targetMails, v.Value)
|
||||
}
|
||||
if targetMails == nil || len(targetMails) == 0 {
|
||||
return
|
||||
}
|
||||
err := em.Send(title, content, targetMails)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
func SendMailTool(c *gin.Context) {
|
||||
id, _ := c.Get("id")
|
||||
id1 := int(id.(float64))
|
||||
|
||||
var req SendMailReq
|
||||
if err := c.ShouldBind(&req); err == nil {
|
||||
user := dao.FindUserByUserID(id1)
|
||||
if user.ID == 0 {
|
||||
c.JSON(http.StatusOK, gin.H{"error": "user not found", "code": proto.ParameterError, "message": "failed"})
|
||||
return
|
||||
}
|
||||
//目标邮箱地址是否合法
|
||||
if !service.CheckEmail(req.To) {
|
||||
c.JSON(http.StatusOK, gin.H{"error": "email address is invalid", "code": proto.ParameterError, "message": "failed"})
|
||||
return
|
||||
}
|
||||
if req.Title == "" || req.Content == "" {
|
||||
c.JSON(http.StatusOK, gin.H{"error": "title or content is empty", "code": proto.ParameterError, "message": "failed"})
|
||||
return
|
||||
}
|
||||
//发送邮件
|
||||
if user.Role == "admin" {
|
||||
go service.SendEmail(req.To, req.Title, req.Content)
|
||||
c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "message": "success", "data": "mail will be sent"})
|
||||
} else {
|
||||
c.JSON(http.StatusOK, gin.H{"error": "no send mail permission", "code": proto.PermissionDenied, "message": "failed"})
|
||||
}
|
||||
} else {
|
||||
c.JSON(http.StatusOK, gin.H{"error": err.Error(), "code": proto.ParameterError, "message": "failed"})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// DownloadProxyHandle 处理下载代理请求
|
||||
func DownloadProxyHandle(c *gin.Context) {
|
||||
key := c.Query("key")
|
||||
if key == "" || key != proto.Config.DOWNLOAD_PROXY_KEY {
|
||||
c.JSON(http.StatusOK, gin.H{"code": proto.ParameterError, "message": "failed, key is null or error"})
|
||||
}
|
||||
// 获取URL参数
|
||||
encodedURL := c.Query("url")
|
||||
if encodedURL == "" {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "URL参数不能为空", "code": proto.ParameterError, "message": "failed"})
|
||||
return
|
||||
}
|
||||
|
||||
// URL解码
|
||||
decodedURL, err := url.QueryUnescape(encodedURL)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "URL解码失败: " + err.Error(), "code": proto.ParameterError, "message": "failed"})
|
||||
return
|
||||
}
|
||||
|
||||
// 验证URL格式
|
||||
parsedURL, err := url.Parse(decodedURL)
|
||||
if err != nil || parsedURL.Scheme == "" || parsedURL.Host == "" {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "无效的URL格式", "code": proto.ParameterError, "message": "failed"})
|
||||
return
|
||||
}
|
||||
|
||||
// 发起请求获取目标资源
|
||||
resp, err := http.Get(decodedURL)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "获取资源失败: " + err.Error(), "code": proto.InternalServerError})
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// 检查响应状态
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
c.JSON(http.StatusBadGateway, gin.H{"error": "目标资源请求失败,状态码: " + resp.Status, "code": proto.InternalServerError})
|
||||
return
|
||||
}
|
||||
|
||||
// 获取文件名
|
||||
filename := getFilenameFromURL(parsedURL)
|
||||
|
||||
// 设置响应头,告诉浏览器这是一个文件下载
|
||||
c.Header("Content-Disposition", "attachment; filename="+url.QueryEscape(filename))
|
||||
c.Header("Content-Type", resp.Header.Get("Content-Type"))
|
||||
c.Header("Content-Length", resp.Header.Get("Content-Length"))
|
||||
|
||||
// 将响应体流式传输到客户端
|
||||
_, err = io.Copy(c.Writer, resp.Body)
|
||||
if err != nil {
|
||||
// 已经开始传输数据后发生错误,无法返回JSON,只能记录日志
|
||||
log.Println("tool download proxy handle error:", err)
|
||||
}
|
||||
}
|
||||
|
||||
// 从URL中提取文件名
|
||||
func getFilenameFromURL(u *url.URL) string {
|
||||
// 从路径中提取文件名
|
||||
filename := filepath.Base(u.Path)
|
||||
// 如果路径中没有文件名,尝试从查询参数中获取
|
||||
if filename == "" || filename == "/" {
|
||||
filename = "download_file"
|
||||
}
|
||||
return filename
|
||||
}
|
||||
|
|
|
|||
228
handler/user.go
228
handler/user.go
|
|
@ -15,8 +15,6 @@ import (
|
|||
"videoplayer/worker"
|
||||
)
|
||||
|
||||
var signingKey = []byte(proto.TOKEN_SECRET)
|
||||
|
||||
func SetUpUserGroup(router *gin.Engine) {
|
||||
userGroup := router.Group("/user")
|
||||
userGroup.POST("/register", registerHandler)
|
||||
|
|
@ -27,6 +25,10 @@ func SetUpUserGroup(router *gin.Engine) {
|
|||
userGroup.POST("/confirm", ConfirmQRLogin)
|
||||
userGroup.POST("/search", SearchHandler)
|
||||
userGroup.POST("/info", GetUserInfo)
|
||||
userGroup.POST("/update", UpdateUserInfo)
|
||||
userGroup.POST("/sync", GetSyncUserInfo)
|
||||
userGroup.POST("/delete", DeleteUser)
|
||||
userGroup.POST("/reset", ResetPassword)
|
||||
}
|
||||
|
||||
type RLReq struct {
|
||||
|
|
@ -47,13 +49,70 @@ type SearchReq struct {
|
|||
Keyword string `json:"keyword" form:"keyword"`
|
||||
ID int `json:"id" form:"id"`
|
||||
}
|
||||
type GetUserInfoReq struct {
|
||||
ID int `json:"id" form:"id"`
|
||||
}
|
||||
|
||||
func GetUserInfo(c *gin.Context) {
|
||||
var req_data GetUserInfoReq
|
||||
id, _ := c.Get("id")
|
||||
user_id := int(id.(float64))
|
||||
user := dao.FindUserByID2(user_id)
|
||||
user.Password = "" //不返回密码
|
||||
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "success", "data": user})
|
||||
if err := c.ShouldBind(&req_data); err == nil {
|
||||
var user dao.User
|
||||
if req_data.ID == user_id {
|
||||
user = dao.FindUserByID2(user_id)
|
||||
user.Password = "" //不返回密码
|
||||
} else {
|
||||
//判断当前用户是否有权限查看
|
||||
cur_user := dao.FindUserByID2(user_id)
|
||||
if cur_user.Role == "admin" {
|
||||
user = dao.FindUserByID2(req_data.ID)
|
||||
user.Password = "" //不返回密码
|
||||
} else {
|
||||
c.JSON(200, gin.H{"code": proto.PermissionDenied, "message": "无权查看", "data": "2"})
|
||||
return
|
||||
}
|
||||
}
|
||||
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "success", "data": user})
|
||||
} else {
|
||||
c.JSON(200, gin.H{"code": proto.ParameterError, "message": err, "data": "2"})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func DeleteUser(c *gin.Context) {
|
||||
var req GetUserInfoReq
|
||||
id, _ := c.Get("id")
|
||||
user_id := int(id.(float64))
|
||||
if err := c.ShouldBind(&req); err == nil {
|
||||
res := service.DeleteUserService(req.ID, user_id)
|
||||
if res != 0 {
|
||||
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "success", "data": res})
|
||||
} else {
|
||||
c.JSON(200, gin.H{"code": proto.OperationFailed, "message": "failed", "data": res})
|
||||
}
|
||||
} else {
|
||||
c.JSON(200, gin.H{"code": proto.ParameterError, "message": err, "data": "2"})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func UpdateUserInfo(c *gin.Context) {
|
||||
var req_data proto.UpdateUserInfoReq
|
||||
id, _ := c.Get("id")
|
||||
user_id := int(id.(float64))
|
||||
if err := c.ShouldBind(&req_data); err == nil {
|
||||
rid, err2 := service.UpdateUser(user_id, req_data)
|
||||
if err2 != nil {
|
||||
c.JSON(200, gin.H{"code": proto.OperationFailed, "message": "failed", "data": "2"})
|
||||
return
|
||||
}
|
||||
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "success", "data": rid})
|
||||
} else {
|
||||
c.JSON(200, gin.H{"code": proto.ParameterError, "message": err, "data": "2"})
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func GetScanUUID(c *gin.Context) {
|
||||
|
|
@ -170,7 +229,7 @@ func GetQRStatus(c *gin.Context) {
|
|||
default:
|
||||
// 解析 JWT 令牌
|
||||
token, err := jwt.Parse(str, func(token *jwt.Token) (interface{}, error) {
|
||||
return signingKey, nil
|
||||
return proto.SigningKey, nil
|
||||
})
|
||||
if err != nil {
|
||||
c.JSON(200, gin.H{"error": err.Error(), "code": proto.TokenParseError, "message": "error"})
|
||||
|
|
@ -230,7 +289,7 @@ func loginHandler(c *gin.Context) {
|
|||
"id": user.ID,
|
||||
"exp": time.Now().Add(time.Hour * 10).Unix(), // 令牌过期时间, 10小时后过期
|
||||
})
|
||||
tokenString, err = token.SignedString(signingKey)
|
||||
tokenString, err = token.SignedString(proto.SigningKey)
|
||||
if err != nil {
|
||||
c.JSON(200, gin.H{"error": err.Error(), "code": proto.TokenGenerationError, "message": "error"})
|
||||
return
|
||||
|
|
@ -287,7 +346,7 @@ func registerHandler(c *gin.Context) {
|
|||
"id": id,
|
||||
"exp": time.Now().Add(time.Hour * 10).Unix(), // 令牌过期时间, 1分钟后过期
|
||||
})
|
||||
tokenString, err = token.SignedString(signingKey)
|
||||
tokenString, err = token.SignedString(proto.SigningKey)
|
||||
if err != nil {
|
||||
c.JSON(200, gin.H{"error": err.Error(), "code": proto.TokenGenerationError, "message": "error"})
|
||||
return
|
||||
|
|
@ -311,3 +370,156 @@ func registerHandler(c *gin.Context) {
|
|||
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "success", "data": data})
|
||||
return
|
||||
}
|
||||
|
||||
func GetSyncUserInfo(c *gin.Context) {
|
||||
var req_data proto.SyncUserReq
|
||||
if err := c.ShouldBind(&req_data); err == nil {
|
||||
if req_data.Token == "" {
|
||||
c.JSON(200, gin.H{"code": proto.ParameterError, "message": "error", "data": "token is empty"})
|
||||
return
|
||||
} else {
|
||||
if worker.IsContainSet("super_permission_tokens", req_data.Token) {
|
||||
if proto.Config.SERVER_USER_TYPE == "master" {
|
||||
if req_data.Types == 1 { //1为全量同步
|
||||
add_users := dao.GetAllUser()
|
||||
resp := dao.UserSyncResp{}
|
||||
resp.Add = add_users
|
||||
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "success", "data": resp})
|
||||
} else if req_data.Types == 2 { //2为增量同步
|
||||
if req_data.Device == "" || worker.IsContainSet("sync_devices_ids", req_data.Device) == false {
|
||||
c.JSON(200, gin.H{"code": proto.ParameterError, "message": "error", "data": "device is empty or not exist"})
|
||||
return
|
||||
}
|
||||
res := service.GetUserSyncData(req_data.Device)
|
||||
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "success", "data": res})
|
||||
} else if req_data.Types == 3 { //3为确认同步数据
|
||||
res := service.ConfirmSyncUserData(req_data.Device, req_data.Confirm)
|
||||
if res == nil {
|
||||
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "success", "data": "success"})
|
||||
} else {
|
||||
c.JSON(200, gin.H{"code": proto.OperationFailed, "message": "failed:" + res.Error(), "data": "failed"})
|
||||
}
|
||||
} else {
|
||||
c.JSON(200, gin.H{"code": proto.ParameterError, "message": "type is error", "data": dao.UserSyncResp{}})
|
||||
}
|
||||
} else {
|
||||
c.JSON(200, gin.H{"code": proto.NoPermission, "message": "no permission,server is not master", "data": proto.UserSync{}})
|
||||
}
|
||||
} else {
|
||||
c.JSON(200, gin.H{"code": proto.NoPermission, "message": "error", "data": "no permission"})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
c.JSON(200, gin.H{"error": err.Error(), "code": proto.ParameterError, "message": "error"})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
type ResetPasswordReq struct {
|
||||
Email string `json:"email" form:"email"`
|
||||
OldPassword string `json:"old_password" form:"old_password"`
|
||||
NewPassword string `json:"new_password" form:"new_password"`
|
||||
Type int `json:"type" form:"type"` //0获取验证码,2为邮箱验证码重置密码,1为旧密码重置密码
|
||||
Code string `json:"code" form:"code"` //验证码
|
||||
}
|
||||
|
||||
func ResetPassword(c *gin.Context) {
|
||||
var req_data ResetPasswordReq
|
||||
if err := c.ShouldBind(&req_data); err == nil {
|
||||
if req_data.Type == 0 {
|
||||
//获取验证码
|
||||
//查看是否存在该邮箱
|
||||
user := dao.FindUserByEmail(req_data.Email)
|
||||
if user.ID == 0 {
|
||||
c.JSON(200, gin.H{"code": proto.OperationFailed, "message": "邮箱不存在", "data": "2"})
|
||||
return
|
||||
}
|
||||
if worker.IsContainKey("reset_password_" + req_data.Email) {
|
||||
c.JSON(200, gin.H{"code": proto.OperationFailed, "message": "验证码已发送,请5分钟后再试", "data": "2"})
|
||||
return
|
||||
}
|
||||
//随机字符串验证码大写
|
||||
code := worker.GetRandomString(6)
|
||||
worker.SetRedisWithExpire("reset_password_"+req_data.Email, code, time.Minute*5) //设置5分钟过期`
|
||||
//发送邮件
|
||||
service.SendEmail(req_data.Email, "大学生学业作品AI生成工具开发重置密码", "验证码:"+code+" ,请在5分钟内使用!")
|
||||
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "success", "data": "2"})
|
||||
return
|
||||
} else if req_data.Type == 1 {
|
||||
//旧密码重置密码
|
||||
if len(req_data.OldPassword) != 32 {
|
||||
hasher := md5.New()
|
||||
hasher.Write([]byte(req_data.OldPassword)) // 生成密码的 MD5 散列值
|
||||
req_data.OldPassword = hex.EncodeToString(hasher.Sum(nil)) // 生成密码的 MD5 散列值
|
||||
}
|
||||
if len(req_data.NewPassword) != 32 {
|
||||
hasher := md5.New()
|
||||
hasher.Write([]byte(req_data.NewPassword)) // 生成密码的 MD5 散列值
|
||||
req_data.NewPassword = hex.EncodeToString(hasher.Sum(nil)) // 生成密码的 MD5 散列值
|
||||
}
|
||||
user := dao.FindUserByEmail(req_data.Email)
|
||||
if user.ID == 0 {
|
||||
c.JSON(200, gin.H{"code": proto.OperationFailed, "message": "邮箱不存在", "data": "2"})
|
||||
return
|
||||
}
|
||||
if user.Password != req_data.OldPassword {
|
||||
c.JSON(200, gin.H{"code": proto.OperationFailed, "message": "旧密码错误", "data": "2"})
|
||||
return
|
||||
}
|
||||
if user.Password == req_data.NewPassword {
|
||||
c.JSON(200, gin.H{"code": proto.OperationFailed, "message": "新旧密码相同", "data": "2"})
|
||||
return
|
||||
}
|
||||
dao.UpdateUserByID(int(user.ID), user.Name, req_data.NewPassword, user.Email)
|
||||
var resp proto.ResponseOAuth
|
||||
token, err2 := service.CreateTokenAndSave(user)
|
||||
if err2 != nil {
|
||||
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "new token error", "data": resp})
|
||||
return
|
||||
}
|
||||
resp.Token = token
|
||||
resp.ID = user.ID
|
||||
resp.Name = user.Name
|
||||
resp.Email = user.Email
|
||||
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "success", "data": resp})
|
||||
} else if req_data.Type == 2 {
|
||||
//邮箱重置密码
|
||||
if len(req_data.NewPassword) != 32 {
|
||||
hasher := md5.New()
|
||||
hasher.Write([]byte(req_data.NewPassword)) // 生成密码的 MD5 散列值
|
||||
req_data.NewPassword = hex.EncodeToString(hasher.Sum(nil)) // 生成密码的 MD5 散列值
|
||||
}
|
||||
user := dao.FindUserByEmail(req_data.Email)
|
||||
if user.ID == 0 {
|
||||
c.JSON(200, gin.H{"code": proto.OperationFailed, "message": "邮箱不存在", "data": "2"})
|
||||
return
|
||||
}
|
||||
code := worker.GetRedis("reset_password_" + req_data.Email)
|
||||
if code != req_data.Code {
|
||||
c.JSON(200, gin.H{"code": proto.OperationFailed, "message": "验证码错误", "data": "2"})
|
||||
return
|
||||
}
|
||||
dao.UpdateUserByID(int(user.ID), user.Name, req_data.NewPassword, user.Email)
|
||||
token, err2 := service.CreateTokenAndSave(user)
|
||||
if err2 != nil {
|
||||
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "new token error", "data": "2"})
|
||||
return
|
||||
}
|
||||
var resp proto.ResponseOAuth
|
||||
resp.Token = token
|
||||
resp.ID = user.ID
|
||||
resp.Name = user.Name
|
||||
resp.Email = user.Email
|
||||
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "success", "data": resp})
|
||||
} else {
|
||||
c.JSON(200, gin.H{"code": proto.OperationFailed, "message": "type error", "data": "2"})
|
||||
return
|
||||
}
|
||||
|
||||
} else {
|
||||
c.JSON(200, gin.H{"code": proto.ParameterError, "message": err, "data": "2"})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,8 +15,9 @@ import (
|
|||
|
||||
// video获取视频列表请求
|
||||
type gvlReq struct {
|
||||
StartTime string `json:"begin" form:"begin"`
|
||||
EndTime string `json:"end" form:"end"`
|
||||
ID int `json:"id" form:"id"`
|
||||
StartTime int64 `json:"begin" form:"begin"`
|
||||
EndTime int64 `json:"end" form:"end"`
|
||||
IP string `json:"ip" form:"ip"`
|
||||
Token string `json:"token" form:"token"`
|
||||
Hour string `json:"hour" form:"hour"`
|
||||
|
|
@ -59,12 +60,13 @@ type videoPReq struct {
|
|||
}
|
||||
|
||||
type VideoDelReq struct {
|
||||
ID int `json:"id"`
|
||||
ID int `json:"id" form:"id"`
|
||||
Type string `json:"type" form:"type"`
|
||||
}
|
||||
|
||||
// video延迟视频请求
|
||||
type delayReq struct {
|
||||
ID int `form:"id"`
|
||||
ID int `json:"id" form:"id"`
|
||||
Option string `form:"option"`
|
||||
AuthId int `form:"userId"`
|
||||
IP string `form:"ip"`
|
||||
|
|
@ -157,7 +159,14 @@ func GetVideoList(c *gin.Context) {
|
|||
gvl_req.Hour = "33"
|
||||
id, _ := c.Get("id")
|
||||
if err := c.ShouldBind(&gvl_req); err == nil {
|
||||
videos := service.GetVideoList(int(id.(float64)), gvl_req.StartTime, gvl_req.EndTime, gvl_req.Hour)
|
||||
const layout = "2006-01-02 15:04:05"
|
||||
tm1 := time.Unix(gvl_req.StartTime, 0).Format(layout)
|
||||
tm2 := time.Unix(gvl_req.EndTime, 0).Format(layout)
|
||||
if gvl_req.StartTime == 0 || gvl_req.EndTime == 0 {
|
||||
tm1 = ""
|
||||
tm2 = ""
|
||||
}
|
||||
videos := service.GetVideoList(int(id.(float64)), gvl_req.ID, tm1, tm2, gvl_req.Hour)
|
||||
c.JSON(http.StatusOK, gin.H{"data": videos, "code": proto.SuccessCode, "message": "success"})
|
||||
} else {
|
||||
c.JSON(http.StatusOK, gin.H{"error": err.Error(), "code": proto.ParameterError, "message": "failed"})
|
||||
|
|
@ -185,7 +194,7 @@ func DelayVideo(c *gin.Context) {
|
|||
} else {
|
||||
data := map[string]interface{}{"auth_id": int(id.(float64)), "method": "delay", "delay_time": time.Now().Format("2006-01-02 15:04:05"), "delay_day": delay_req.Day, "option": delay_req.Option, "id": delay_req.ID}
|
||||
str, _ := json.Marshal(data)
|
||||
worker.PushRedisList(user.(string)+"-"+strconv.Itoa(int(id.(float64)))+"-option", string(str))
|
||||
service.SetVideoOption(user.(string)+"-"+strconv.Itoa(int(id.(float64)))+"-option", string(str))
|
||||
c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "data": "延迟成功,影响记录:" + strconv.Itoa(cnt), "message": "success cnt:" + strconv.Itoa(cnt)})
|
||||
}
|
||||
} else {
|
||||
|
|
@ -196,34 +205,30 @@ func DelayVideo(c *gin.Context) {
|
|||
func DeleteVideo(c *gin.Context) {
|
||||
var video_req VideoDelReq
|
||||
id, _ := c.Get("id")
|
||||
user, _ := c.Get("username")
|
||||
if err := c.ShouldBind(&video_req); err == nil {
|
||||
res := service.DeleteVideo(video_req.ID, int(id.(float64)))
|
||||
res := service.DeleteVideo(video_req.ID, int(id.(float64)), video_req.Type)
|
||||
if res != 0 {
|
||||
data := map[string]interface{}{"id": video_req.ID, "auth_id": int(id.(float64)), "delete_time": time.Now().Format("2006-01-02 15:04:05"), "method": "delete"}
|
||||
str, _ := json.Marshal(data)
|
||||
worker.PushRedisList(user.(string)+"-"+strconv.Itoa(int(id.(float64)))+"-option", string(str))
|
||||
c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "message": "success"})
|
||||
c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "msg": "success", "data": "delete video success"})
|
||||
} else {
|
||||
c.JSON(http.StatusOK, gin.H{"code": proto.ParameterError, "message": "failed"})
|
||||
c.JSON(http.StatusOK, gin.H{"code": proto.ParameterError, "msg": "failed", "data": "delete video failed"})
|
||||
}
|
||||
} else {
|
||||
c.JSON(http.StatusOK, gin.H{"error": err.Error(), "code": proto.ParameterError, "message": "failed"})
|
||||
c.JSON(http.StatusOK, gin.H{"error": err.Error(), "code": proto.ParameterError, "msg": err, "data": "failed"})
|
||||
}
|
||||
}
|
||||
|
||||
func QuashOption(c *gin.Context) {
|
||||
id, _ := c.Get("id")
|
||||
user, _ := c.Get("username")
|
||||
res := worker.PopRedisList(user.(string) + "-" + strconv.Itoa(int(id.(float64))) + "-option")
|
||||
id1 := int(id.(float64))
|
||||
res := worker.PopRedisList("user-" + strconv.Itoa(int(id.(float64))) + "-option")
|
||||
if res != "" {
|
||||
var retrievedData map[string]interface{}
|
||||
err2 := json.Unmarshal([]byte(res), &retrievedData)
|
||||
if err2 == nil {
|
||||
code, msg := service.QuashVideo(int(id.(float64)), retrievedData)
|
||||
code, msg := service.QuashVideo(id1, retrievedData)
|
||||
c.JSON(http.StatusOK, gin.H{"code": code, "message": msg, "data": msg})
|
||||
} else {
|
||||
worker.PushRedisList(user.(string)+"-"+strconv.Itoa(int(id.(float64)))+"-option", res) //未操作成功重新添加到队列
|
||||
worker.PushRedisList("user-"+strconv.Itoa(int(id.(float64)))+"-option", res) //未操作成功重新添加到队列
|
||||
c.JSON(http.StatusOK, gin.H{"code": proto.ParameterError, "message": err2, "data": "json解析错误"})
|
||||
return
|
||||
}
|
||||
|
|
|
|||
339
main.go
339
main.go
|
|
@ -1,48 +1,109 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/golang-jwt/jwt"
|
||||
"github.com/robfig/cron/v3"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"videoplayer/dao"
|
||||
"videoplayer/handler"
|
||||
"videoplayer/proto"
|
||||
"videoplayer/service"
|
||||
"videoplayer/worker"
|
||||
)
|
||||
|
||||
var signingKey = []byte(proto.TOKEN_SECRET)
|
||||
|
||||
func main() {
|
||||
|
||||
r := gin.Default()
|
||||
// 输入参数
|
||||
if len(os.Args) > 1 {
|
||||
initConfig(os.Args[1]) //第一个参数是配置文件路径
|
||||
} else {
|
||||
initConfig("") //没有输入参数,则使用默认配置文件路径
|
||||
}
|
||||
gin.SetMode(gin.ReleaseMode)
|
||||
r := gin.Default()
|
||||
err := dao.Init()
|
||||
if err != nil {
|
||||
panic("failed to connect database:" + err.Error())
|
||||
}
|
||||
err = worker.InitRedis()
|
||||
if err != nil {
|
||||
panic("failed to connect redis:" + err.Error())
|
||||
if proto.Config.MEMORY_CACHE == false { //不开启内存缓存,才使用redis
|
||||
err = worker.InitRedis()
|
||||
if err != nil {
|
||||
panic("failed to connect redis:" + err.Error())
|
||||
}
|
||||
}
|
||||
r.Use(handler.CrosHandler())
|
||||
r.Use(JWTAuthMiddleware()) // 使用 JWT 认证中间件
|
||||
handler.SetUpVideoGroup(r) // Video
|
||||
handler.SetUpUserGroup(r) // User
|
||||
r.Use(JWTAuthMiddleware()) // 使用 JWT 认证中间件
|
||||
handler.SetUpVideoGroup(r) // Video
|
||||
//handler.SetUpUserGroup(r) // User
|
||||
handler.SetUpDeviceGroup(r) // Device
|
||||
handler.SetUpIMGroup(r) // IM
|
||||
handler.SetUpCIDGroup(r) // CID,持续集成、部署
|
||||
handler.SetUpToolGroup(r) // Tool
|
||||
r.Run(":8083") // listen and serve on 0.0.0.0:8083
|
||||
handler.SetUpFileGroup(r) // File
|
||||
handler.SetUpShellGroup(r) // Shell
|
||||
handler.SetDBManageGroup(r) // DBM
|
||||
defer dao.Close()
|
||||
defer worker.CloseRedis()
|
||||
//定时任务
|
||||
c := cron.New(cron.WithSeconds())
|
||||
// 添加每 10 秒执行一次的任务
|
||||
_, err = c.AddFunc("@every 10s", myTask)
|
||||
if err != nil {
|
||||
log.Fatal("添加定时任务失败: ", err)
|
||||
}
|
||||
c.Start()
|
||||
//读取配置文件,设置系统
|
||||
ReadConfigToSetSystem()
|
||||
r.Run(":" + proto.Config.SERVER_PORT) // listen and serve on 0.0.0.0:8083
|
||||
}
|
||||
func init() {
|
||||
|
||||
// 不使用
|
||||
//
|
||||
// func init() {
|
||||
// // 创建cid的目录
|
||||
// os.MkdirAll(proto.CID_BASE_DIR, os.ModePerm)
|
||||
// os.MkdirAll(proto.CID_BASE_DIR+"script", os.ModePerm)
|
||||
// os.MkdirAll(proto.CID_BASE_DIR+"workspace", os.ModePerm)
|
||||
// //读取配置文件
|
||||
// //文件地址/home/videoplayer/vp.conf
|
||||
// configPath := "/home/videoplayer/vp.conf"
|
||||
// //读取配置文件
|
||||
// err := proto.ReadConfig(configPath)
|
||||
// if err != nil {
|
||||
// panic("failed to read config file:" + err.Error())
|
||||
// }
|
||||
// }
|
||||
func initConfig(configPath string) {
|
||||
//if proto.Config.TOKEN_SECRET != "" {
|
||||
// return
|
||||
//}
|
||||
// 创建cid的目录
|
||||
os.MkdirAll(proto.CID_BASE_DIR, os.ModePerm)
|
||||
os.MkdirAll(proto.CID_BASE_DIR+"script", os.ModePerm)
|
||||
os.MkdirAll(proto.CID_BASE_DIR+"workspace", os.ModePerm)
|
||||
//系统是linux、macos还是windows
|
||||
if configPath == "" {
|
||||
if os.Getenv("OS") == "Windows_NT" {
|
||||
configPath = "C:/Users/Administrator/vp.conf"
|
||||
} else if os.Getenv("OS") == "linux" {
|
||||
//文件地址/home/saw-ai/saw-ai.conf
|
||||
configPath = "/etc/vp.conf"
|
||||
} else {
|
||||
configPath = "/etc/vp.conf"
|
||||
}
|
||||
}
|
||||
//读取配置文件
|
||||
err := proto.ReadConfig(configPath)
|
||||
if err != nil {
|
||||
panic("failed to read config file:" + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func writeLogger(c *gin.Context) {
|
||||
|
|
@ -71,7 +132,9 @@ func writeLogger(c *gin.Context) {
|
|||
|
||||
func JWTAuthMiddleware() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
writeLogger(c)
|
||||
if proto.Config.LOG_SAVE_DAYS > 0 {
|
||||
writeLogger(c)
|
||||
}
|
||||
// 从请求头中获取 JWT 令牌
|
||||
tokenString := c.Request.Header.Get("token")
|
||||
|
||||
|
|
@ -79,42 +142,62 @@ func JWTAuthMiddleware() gin.HandlerFunc {
|
|||
if tokenString == "" {
|
||||
tokenString = c.Query("token")
|
||||
}
|
||||
|
||||
//如果请求为login或register,则不需要验证token
|
||||
if strings.Contains(c.Request.URL.Path, "/login") || strings.Contains(c.Request.URL.Path, "/register") || strings.Contains(c.Request.URL.Path, "/uuid") || strings.Contains(c.Request.URL.Path, "/gqr") || strings.Contains(c.Request.URL.Path, "/cid/callback") {
|
||||
//for k, _ := range proto.Url_map {
|
||||
// if strings.Contains(c.Request.URL.Path, k) {
|
||||
// c.Next()
|
||||
// return
|
||||
// }
|
||||
//}
|
||||
if proto.Url_map[c.Request.URL.Path] == true { //查看是否在不需要token的url中
|
||||
c.Next()
|
||||
return
|
||||
}
|
||||
if proto.SigningKeyIsValid == false {
|
||||
c.AbortWithStatusJSON(http.StatusOK, gin.H{"message": "server error", "error": "token secret is invalid", "code": proto.SigningKeyIsValid})
|
||||
return
|
||||
}
|
||||
if tokenString == "" {
|
||||
//c.AbortWithStatus(200)
|
||||
c.JSON(200, gin.H{
|
||||
"message": "Unauthorized",
|
||||
"error": "token is empty",
|
||||
"code": proto.TokenIsNull,
|
||||
})
|
||||
c.JSON(http.StatusOK, gin.H{"message": "Unauthorized", "error": "token is empty", "code": proto.TokenIsNull})
|
||||
return
|
||||
}
|
||||
redisToken := worker.GetRedis(tokenString)
|
||||
if proto.Config.TOKEN_USE_REDIS {
|
||||
redisToken := worker.GetRedis(tokenString)
|
||||
if redisToken == "" {
|
||||
c.AbortWithStatusJSON(http.StatusOK, gin.H{"message": "NOT_LOGIN", "error": "server token is empty", "code": proto.TokenIsNull})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if redisToken == "" {
|
||||
c.AbortWithStatus(200)
|
||||
c.JSON(200, gin.H{
|
||||
"message": "NOT_LOGIN",
|
||||
"error": "server token is empty",
|
||||
"code": proto.TokenIsNull,
|
||||
})
|
||||
//查看token是否在超级token中
|
||||
if worker.IsContainSet("super_permission_tokens", tokenString) {
|
||||
sId := c.Request.Header.Get("super_id")
|
||||
if sId == "" {
|
||||
sId = c.Query("super_id")
|
||||
}
|
||||
if sId == "" {
|
||||
c.AbortWithStatusJSON(http.StatusOK, gin.H{"message": "unauthorized", "error": "super_id is empty", "code": proto.TokenIsNull})
|
||||
return
|
||||
}
|
||||
id, _ := strconv.Atoi(sId)
|
||||
idFloat64 := float64(id)
|
||||
//查看s_id类型
|
||||
c.Set("id", idFloat64)
|
||||
c.Next()
|
||||
return
|
||||
}
|
||||
|
||||
// 解析 JWT 令牌
|
||||
proto.SigningKeyRWLock.RLock() //加读锁
|
||||
// 使用加密secret 解析 JWT 令牌
|
||||
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
|
||||
return signingKey, nil
|
||||
return proto.SigningKey, nil
|
||||
})
|
||||
proto.SigningKeyRWLock.RUnlock()
|
||||
|
||||
// 验证令牌
|
||||
if err != nil || !token.Valid {
|
||||
c.AbortWithStatus(200)
|
||||
c.JSON(200, gin.H{
|
||||
c.AbortWithStatusJSON(http.StatusOK, gin.H{
|
||||
"message": "NOT_LOGIN",
|
||||
"error": "Invalid token",
|
||||
"code": proto.TokenExpired,
|
||||
|
|
@ -126,7 +209,199 @@ func JWTAuthMiddleware() gin.HandlerFunc {
|
|||
c.Set("id", token.Claims.(jwt.MapClaims)["id"])
|
||||
c.Set("username", token.Claims.(jwt.MapClaims)["username"])
|
||||
|
||||
if UserFuncIntercept(int(token.Claims.(jwt.MapClaims)["id"].(float64)), c.Request.URL.Path) {
|
||||
c.AbortWithStatusJSON(http.StatusOK, gin.H{
|
||||
"message": "no function permission",
|
||||
"error": "no permission",
|
||||
"code": proto.NoPermission,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 继续处理请求
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
func myTask() {
|
||||
// 定时任务
|
||||
//redis中取出数据
|
||||
handler.RunCron()
|
||||
if proto.Config.MONITOR {
|
||||
handler.ScanDeviceStatus()
|
||||
}
|
||||
//其它定时任务-通用
|
||||
RunGeneralCron()
|
||||
service.ShellWillRunFromServer()
|
||||
service.SyncTokenSecretFromUserCenter()
|
||||
service.DelDBMMap() //定时处理DBMMap中的数据
|
||||
if proto.Config.MEMORY_CACHE {
|
||||
worker.DeleteMemoryCacheCron()
|
||||
// 清理后持久化
|
||||
worker.WriteMemoryCacheToFile()
|
||||
}
|
||||
}
|
||||
|
||||
func ReadConfigToSetSystem() {
|
||||
//将当前配置文件的信息写入redis,用于程序运行时排查
|
||||
config_json, c_err := json.Marshal(proto.Config)
|
||||
if c_err != nil {
|
||||
fmt.Println("ReadConfigToSetSystem Error encoding config,err :", c_err)
|
||||
} else {
|
||||
worker.SetRedis("system_config_info", string(config_json))
|
||||
}
|
||||
|
||||
//redis添加通用定时任务
|
||||
key := "cron_info"
|
||||
//日志清理
|
||||
res := worker.GetRedis(key)
|
||||
var cron_infos []proto.CronInfo
|
||||
if res != "" {
|
||||
err := json.Unmarshal([]byte(res), &cron_infos)
|
||||
if err != nil {
|
||||
fmt.Println("ReadConfigToSetSystem Error decoding config,key value is :", res)
|
||||
}
|
||||
|
||||
//查看清除日志任务是否存在
|
||||
if proto.Config.LOG_SAVE_DAYS > 0 {
|
||||
var is_exist bool
|
||||
for _, v := range cron_infos {
|
||||
if v.Type == 1 {
|
||||
is_exist = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !is_exist {
|
||||
var logClean proto.CronInfo
|
||||
logClean.Type = 1
|
||||
logClean.Info = "日志清理"
|
||||
logClean.Curr = 86400
|
||||
logClean.Every = 86400
|
||||
cron_infos = append(cron_infos, logClean)
|
||||
}
|
||||
}
|
||||
|
||||
is_exist := false
|
||||
user_sync_id := -1 //用户同步任务索引
|
||||
for i, v := range cron_infos {
|
||||
if v.Type == 2 {
|
||||
is_exist = true
|
||||
if proto.Config.USER_SYNC_TIME != v.Every {
|
||||
v.Every = proto.Config.USER_SYNC_TIME
|
||||
v.Curr = proto.Config.USER_SYNC_TIME
|
||||
}
|
||||
user_sync_id = i
|
||||
cron_infos[i] = v
|
||||
break
|
||||
}
|
||||
}
|
||||
if proto.Config.SERVER_USER_TYPE == "slave" {
|
||||
if proto.Config.USER_SYNC_TIME > 0 && !is_exist {
|
||||
var userSync proto.CronInfo
|
||||
userSync.Type = 2
|
||||
userSync.Info = "user"
|
||||
userSync.Curr = proto.Config.USER_SYNC_TIME
|
||||
userSync.Every = proto.Config.USER_SYNC_TIME
|
||||
cron_infos = append(cron_infos, userSync)
|
||||
} else if user_sync_id != -1 {
|
||||
cron_infos = append(cron_infos[:user_sync_id], cron_infos[user_sync_id+1:]...) //删除
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
if proto.Config.LOG_SAVE_DAYS > 0 {
|
||||
var logClean proto.CronInfo
|
||||
logClean.Type = 1
|
||||
logClean.Info = "日志清理"
|
||||
logClean.Curr = 86400
|
||||
logClean.Every = 86400
|
||||
cron_infos = append(cron_infos, logClean)
|
||||
}
|
||||
if proto.Config.SERVER_USER_TYPE == "slave" && proto.Config.USER_SYNC_TIME > 0 {
|
||||
var userSync proto.CronInfo
|
||||
userSync.Type = 2
|
||||
userSync.Info = "user"
|
||||
userSync.Curr = proto.Config.USER_SYNC_TIME
|
||||
userSync.Every = proto.Config.USER_SYNC_TIME
|
||||
cron_infos = append(cron_infos, userSync)
|
||||
}
|
||||
}
|
||||
//存入redis
|
||||
json_data, err := json.Marshal(cron_infos)
|
||||
if err != nil {
|
||||
fmt.Println("ReadConfigToSetSystem Error encoding config,value is :", cron_infos)
|
||||
} else {
|
||||
worker.SetRedis(key, string(json_data))
|
||||
}
|
||||
}
|
||||
|
||||
func RunGeneralCron() {
|
||||
//redis添加通用定时任务
|
||||
key := "cron_info"
|
||||
//日志清理
|
||||
res := worker.GetRedis(key)
|
||||
var cron_infos []proto.CronInfo
|
||||
if res != "" {
|
||||
err := json.Unmarshal([]byte(res), &cron_infos)
|
||||
if err != nil {
|
||||
fmt.Println("RunGeneralCron Error decoding config,key value is :", res)
|
||||
}
|
||||
for i, v := range cron_infos {
|
||||
//1:日志清理,其他待定
|
||||
if v.Type == 1 {
|
||||
//日志清理
|
||||
if v.Curr <= 0 {
|
||||
//执行日志清理
|
||||
go dao.DeleteLog(proto.Config.LOG_SAVE_DAYS)
|
||||
v.Curr = v.Every
|
||||
} else {
|
||||
v.Curr -= 10
|
||||
}
|
||||
cron_infos[i] = v
|
||||
continue
|
||||
}
|
||||
//2 从服务器同步数据
|
||||
if v.Type == 2 {
|
||||
if v.Curr <= 0 {
|
||||
//执行从服务器同步数据
|
||||
if proto.Config.SERVER_USER_TYPE == "slave" && v.Info == "user" {
|
||||
go service.UserSyncDataFromMaster()
|
||||
}
|
||||
v.Curr = v.Every
|
||||
} else {
|
||||
v.Curr -= 10
|
||||
}
|
||||
cron_infos[i] = v
|
||||
continue
|
||||
}
|
||||
}
|
||||
//存入redis
|
||||
json_data, err := json.Marshal(cron_infos)
|
||||
if err != nil {
|
||||
fmt.Println("RunGeneralCron Error encoding config,value is :", cron_infos)
|
||||
} else {
|
||||
worker.SetRedis(key, string(json_data))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 用户功能拦截,返回true表示拦截,false表示不拦截
|
||||
func UserFuncIntercept(id int, url string) bool {
|
||||
//先查看是否有权限
|
||||
user := service.GetUserByIDFromUserCenter(id)
|
||||
//如果用户有权限,则不拦截
|
||||
for k, v := range proto.Per_menu_map {
|
||||
if strings.Contains(url, k) {
|
||||
if v == 1 && user.VideoFunc <= 0 {
|
||||
return true
|
||||
}
|
||||
if v == 2 && user.DeviceFunc <= 0 {
|
||||
return true
|
||||
}
|
||||
if v == 3 && user.CIDFunc <= 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
|
|||
147
proto/conf.go
147
proto/conf.go
|
|
@ -1,17 +1,41 @@
|
|||
package proto
|
||||
|
||||
import "gorm.io/gorm"
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"gorm.io/gorm"
|
||||
"log"
|
||||
mrand "math/rand"
|
||||
"os"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var Config ConfigStruct
|
||||
var SigningKey = []byte{}
|
||||
var Url_map = map[string]bool{"/login": true, "/register": true, "/uuid": true, "/gqr": true, "/cid/callback": true, "/tool/monitor": true, "/user/sync": true, "/tool/file/": true, "/user/reset": true, "/tool/dlp": true} // 不需要token验证的url
|
||||
var Per_menu_map = map[string]int{"/video/": 1, "/device/": 2, "/cid/": 3}
|
||||
var File_Type = map[string]int{"im": 1, "avatar": 2, "file": 3, "config": 4} // 文件类型
|
||||
var CID_Running_Map = map[int][]CIDRunning{} //正在运行的cid
|
||||
|
||||
// 配置读写锁
|
||||
var CID_RunningMutex = sync.RWMutex{}
|
||||
var ConfigRWLock = &sync.RWMutex{}
|
||||
var SigningKeyRWLock = &sync.RWMutex{}
|
||||
|
||||
var SyncSecretReqLog int64
|
||||
var CurrentConfigPath string
|
||||
var SigningKeyIsValid = true // 是否有效的签名密钥
|
||||
|
||||
const (
|
||||
MYSQL_USER = "video_t2"
|
||||
MYSQL_DB = "video_t2"
|
||||
MYSQL_PASSWORD = "2t2SKHmWEYj2xFKF"
|
||||
MYSQL_PASSWORD = "2fdreYj2xFKF"
|
||||
MYSQL_PORT = "3306"
|
||||
MYSQL_HOST = "127.0.0.1"
|
||||
MYSQL_DSN = MYSQL_USER + ":" + MYSQL_PASSWORD + "@tcp(" + MYSQL_HOST + ":" + MYSQL_PORT + ")/" + MYSQL_DB + "?charset=utf8mb4&parseTime=True&loc=Local"
|
||||
|
||||
REDIS_ADDR = "127.0.0.1:6379"
|
||||
REDIS_PASSWORD = "lj502138"
|
||||
REDIS_PASSWORD = "lgybvueiogvter"
|
||||
REIDS_DB = 2
|
||||
|
||||
TOKEN_SECRET = "mfjurnc_32ndj9dfhj"
|
||||
|
|
@ -21,6 +45,8 @@ const (
|
|||
|
||||
// 以下是文件上传的配置
|
||||
FILE_BASE_DIR = "/home/lijun/file/"
|
||||
|
||||
DBMMap_Max_Keep_Time = 10 * 60 //DBMap中的数据最大保持时间,10min
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
@ -51,3 +77,118 @@ type User struct {
|
|||
Email string `gorm:"column:email"`
|
||||
Gender string `gorm:"column:gender"`
|
||||
}
|
||||
type StructValue struct {
|
||||
Value string `json:"value" form:"value"`
|
||||
}
|
||||
|
||||
type ConfigStruct struct {
|
||||
DB int `json:"db"` // 0: mysql, 1: pg, 2:sqlite
|
||||
MYSQL_DSN string `json:"mysql_dsn"`
|
||||
PG_DSN string `json:"pg_dsn"`
|
||||
SQLITE_FILE string `json:"sqlite_file"`
|
||||
REDIS_ADDR string `json:"redis_addr"`
|
||||
TOKEN_USE_REDIS bool `json:"token_use_redis"`
|
||||
REDIS_User_PW bool `json:"redis_user_pw"` // 是否使用密码
|
||||
REDIS_PASSWORD string `json:"redis_password"`
|
||||
MEMORY_CACHE bool `json:"memory_cache"` //使用程序内缓存,开启这个redis将不生效
|
||||
REDIS_DB int `json:"redis_db"`
|
||||
TOKEN_SECRET string `json:"token_secret"`
|
||||
CID_BASE_DIR string `json:"cid_base_dir"`
|
||||
FILE_BASE_DIR string `json:"file_base_dir"`
|
||||
MONITOR bool `json:"monitor"` // 状态监控及邮件通知
|
||||
SERVER_SQL_LOG bool `json:"server_sql_log"` // 服务器sql日志
|
||||
SERVER_PORT string `json:"server_port"` // 服务端口
|
||||
LOG_SAVE_DAYS int `json:"log_save_days"` // 日志保存天数,-1表示不保存,0表示永久保存
|
||||
SERVER_USER_TYPE string `json:"user_type"` // 服务器用户类型,master: 主服务器,slave: 从服务器,从服务器会定时同步数据
|
||||
MASTER_SERVER_DOMAIN string `json:"master_server_domain"` // 主服务器域名
|
||||
USER_SYNC_TIME int `json:"user_sync_time"` // 用户数据同步时间,单位秒
|
||||
SERVER_NAME string `json:"server_name"` // 服务器名称,用于区分不同服务器
|
||||
MONITOR_SERVER_TOKEN string `json:"monitor_server_token"` // 监控服务器token,用于状态监控及邮件通知
|
||||
APP_ID string `json:"app_id"` // 应用ID,用于标识不同应用
|
||||
MONITOR_MAIL []StructValue `json:"monitor_mail"` // 设备监控邮件通知配置
|
||||
DOWNLOAD_PROXY_KEY string `json:"download_proxy_key"` // 下载代理key
|
||||
}
|
||||
|
||||
func WriteConfigToFile() {
|
||||
configData, err := json.MarshalIndent(Config, "", " ")
|
||||
if err != nil {
|
||||
log.Println("WriteConfigToFile json marshal error:", err)
|
||||
return
|
||||
}
|
||||
err = os.WriteFile(CurrentConfigPath, configData, 0644)
|
||||
if err != nil {
|
||||
log.Println("WriteConfigToFile write file error:", err)
|
||||
return
|
||||
}
|
||||
log.Println("WriteConfigToFile write config to file success")
|
||||
}
|
||||
|
||||
// 读取配置文件
|
||||
func ReadConfig(path string) error {
|
||||
//查看配置文件是否存在,不存在则创建
|
||||
CurrentConfigPath = path
|
||||
_, err := os.Stat(path)
|
||||
if err != nil {
|
||||
fmt.Println("Config file not found!")
|
||||
//创建默认配置
|
||||
DefaultConfig()
|
||||
WriteConfigToFile()
|
||||
}
|
||||
|
||||
//读json文件
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
fmt.Println("Error opening config file")
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
decoder := json.NewDecoder(file)
|
||||
err = decoder.Decode(&Config)
|
||||
if err != nil {
|
||||
fmt.Println("Error decoding config")
|
||||
} else {
|
||||
if Config.SERVER_PORT == "" {
|
||||
Config.SERVER_PORT = "8083" // 默认端口
|
||||
}
|
||||
}
|
||||
SigningKey = []byte(Config.TOKEN_SECRET)
|
||||
if Config.APP_ID == "" {
|
||||
Config.APP_ID = GetRandomString(8)
|
||||
log.Println("ReadConfig generated APP_ID:", Config.APP_ID)
|
||||
go WriteConfigToFile()
|
||||
}
|
||||
return err
|
||||
}
|
||||
func GetRandomString(l int) string {
|
||||
str := "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
bytes := []byte(str)
|
||||
var result []byte
|
||||
for i := 0; i < l; i++ {
|
||||
result = append(result, bytes[mrand.Intn(len(bytes))])
|
||||
}
|
||||
return string(result)
|
||||
}
|
||||
|
||||
// 默认配置
|
||||
func DefaultConfig() {
|
||||
Config.DB = 2
|
||||
Config.MYSQL_DSN = MYSQL_DSN
|
||||
Config.PG_DSN = ""
|
||||
Config.REDIS_ADDR = REDIS_ADDR
|
||||
Config.SQLITE_FILE = ""
|
||||
Config.TOKEN_USE_REDIS = false
|
||||
Config.REDIS_User_PW = false
|
||||
Config.REDIS_PASSWORD = REDIS_PASSWORD
|
||||
Config.REDIS_DB = REIDS_DB
|
||||
Config.TOKEN_SECRET = TOKEN_SECRET
|
||||
Config.CID_BASE_DIR = CID_BASE_DIR
|
||||
Config.FILE_BASE_DIR = FILE_BASE_DIR
|
||||
Config.MONITOR = false
|
||||
Config.SERVER_SQL_LOG = false
|
||||
Config.SERVER_PORT = "8083"
|
||||
Config.LOG_SAVE_DAYS = 7
|
||||
Config.SERVER_USER_TYPE = "master"
|
||||
Config.MASTER_SERVER_DOMAIN = ""
|
||||
Config.USER_SYNC_TIME = 86400
|
||||
Config.SERVER_NAME = "default"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,118 @@
|
|||
package proto
|
||||
|
||||
import (
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
const (
|
||||
DB_TYPE_MYSQL = 0 // DBTypeMySQL MySQL数据库
|
||||
DB_TYPE_POSTGRES = 1 // DBTypePostgres PostgreSQL数据库
|
||||
DB_TYPE_SQLITE = 2 // DBTypeSQLite SQLite数据库
|
||||
DB_TYPE_SQLSERVER = 3 // DBTypeSQLServer SQL Server数据库
|
||||
DB_TYPE_ORACLE = 4 // DBTypeOracle Oracle数据库
|
||||
DB_TYPE_MONGODB = 5 // DBTypeMongoDB MongoDB数据库
|
||||
DB_TYPE_REDIS = 6 // DBTypeRedis Redis数据库
|
||||
)
|
||||
|
||||
type RunSQLRequest struct {
|
||||
SQL string `json:"sql" form:"sql"` // SQL语句
|
||||
DB_ID uint `json:"db_id" form:"db_id"` // 数据库ID
|
||||
UserID uint `json:"user_id" form:"user_id"` // 用户ID
|
||||
}
|
||||
|
||||
type DBManage struct {
|
||||
gorm.Model
|
||||
UserID uint `gorm:"column:user_id"` // 用户ID
|
||||
DB_IP string `gorm:"column:db_ip;type:varchar(255)"` // 数据库IP
|
||||
DB_Port uint `gorm:"column:db_port"` // 数据库端口
|
||||
DB_NAME string `gorm:"column:db_name;type:varchar(255);uniqueIndex:idx_db_name"` // 数据库名称
|
||||
DB_User string `gorm:"column:db_user;type:varchar(255);uniqueIndex:idx_db_user"` // 数据库用户名
|
||||
DB_Password string `gorm:"column:db_password;type:varchar(255);uniqueIndex:idx_db_password"` // 数据库密码
|
||||
DB_Type uint `gorm:"column:db_type"` // 数据库类型: 0为mysql,1为postgres,2为sqlite,3为sqlserver,4为oracle,5为mongodb,6为redis
|
||||
DB_Desc string `gorm:"column:db_desc;type:varchar(255)"` // 数据库描述
|
||||
DB_STATUS uint `gorm:"column:db_status"` // 数据库状态: 0为未连接,1为已连接,2为连接失败
|
||||
}
|
||||
|
||||
type SQLRunHistory struct {
|
||||
gorm.Model
|
||||
UserID uint `gorm:"column:user_id"` // 用户ID
|
||||
SQL string `gorm:"column:sql;type:text"` // 执行的SQL语句
|
||||
DB_ID uint `gorm:"column:db_id"` // 数据库ID
|
||||
Status uint `gorm:"column:status"` // 执行状态: 0为成功,1为失败
|
||||
}
|
||||
|
||||
type CreateDBManageReq struct {
|
||||
DB_IP string `json:"db_ip" form:"db_ip"` // 数据库IP
|
||||
DB_Port uint `json:"db_port" form:"db_port"` // 数据库端口
|
||||
DB_NAME string `json:"db_name" form:"db_name"` // 数据库名称
|
||||
DB_User string `json:"db_user" form:"db_user"` // 数据库用户名
|
||||
DB_Password string `json:"db_password" form:"db_password"` // 数据库密码
|
||||
DB_Type uint `json:"db_type" form:"db_type"` // 数据库类型: 0为mysql,1为postgres,2为sqlite,3为sqlserver,4为oracle,5为mongodb,6为redis
|
||||
DB_Desc string `json:"db_desc" form:"db_desc"` // 数据库描述备注
|
||||
}
|
||||
|
||||
type UpdateDBManageReq struct {
|
||||
DB_ID uint `json:"db_id" form:"db_id"` // 数据库ID
|
||||
DB_IP string `json:"db_ip" form:"db_ip"` // 数据库IP
|
||||
DB_Port uint `json:"db_port" form:"db_port"` // 数据库端口
|
||||
DB_NAME string `json:"db_name" form:"db_name"` // 数据库名称
|
||||
DB_User string `json:"db_user" form:"db_user"` // 数据库用户名
|
||||
DB_Password string `json:"db_password" form:"db_password"` // 数据库密码
|
||||
DB_Type uint `json:"db_type" form:"db_type"` // 数据库类型: 0为mysql,1为postgres,2为sqlite,3为sqlserver,4为oracle,5为mongodb,6为redis
|
||||
DB_Desc string `json:"db_desc" form:"db_desc"` // 数据库描述备注
|
||||
}
|
||||
|
||||
type GetDBManageReq struct {
|
||||
DB_ID uint `json:"db_id" form:"db_id"` // 数据库ID
|
||||
GET_TYPE int `json:"get_type" form:"get_type"` // 获取类型: 0获取自己,1为获取全部(管理员权限)
|
||||
}
|
||||
|
||||
type GetSQLRunHistoryReq struct {
|
||||
DB_ID uint `json:"db_id" form:"db_id"` // 数据库ID
|
||||
GET_TYPE int `json:"get_type" form:"get_type"` // 获取类型: 0获取自己,1为获取全部(管理员权限)
|
||||
}
|
||||
|
||||
// SQLResult 包含查询结果的列名顺序和对应数据
|
||||
type SQLResult struct {
|
||||
Columns []SQLResultColumnsValue // 列名顺序(与 SQL 查询的列顺序一致)
|
||||
Rows []map[string]interface{} // 每行数据(map 便于按列名访问)
|
||||
}
|
||||
|
||||
type SQLResultColumnsValue struct {
|
||||
Prop string `json:"prop"`
|
||||
Label string `json:"label"`
|
||||
Attr string `json:"attr"`
|
||||
}
|
||||
|
||||
type DeleteDBManageReq struct {
|
||||
DB_ID uint `json:"db_id" form:"db_id"` // 数据库ID
|
||||
Del_Type uint `json:"del_type" form:"del_type"` // 删除类型: 0为删除单条,1为所有
|
||||
UserID uint `json:"user_id" form:"user_id"` // 用户ID
|
||||
}
|
||||
|
||||
type DeleteDBManageSQLHistoryReq struct {
|
||||
DB_ID uint `json:"db_id" form:"db_id"` // 数据库ID
|
||||
Del_Type uint `json:"del_type" form:"del_type"` // 删除类型: 0为删除单条,1为所有
|
||||
History_ID uint `json:"history_id" form:"history_id"` // SQL执行历史ID,如果为0则删除所有
|
||||
UserID uint `json:"user_id" form:"user_id"` // 用户ID
|
||||
}
|
||||
|
||||
type GetDBTableDescReq struct {
|
||||
DB_ID uint `json:"db_id" form:"db_id"` // 数据库ID
|
||||
Table string `json:"table" form:"table"` // 数据库表名
|
||||
GetType int `json:"get_type" form:"get_type"` // 获取类型: 0获取全部,1获取1个
|
||||
}
|
||||
|
||||
type GetDBTableDescResp struct {
|
||||
TableName string `json:"table_name"` // 表名
|
||||
}
|
||||
|
||||
type DBTableAttribute struct {
|
||||
ColumnName string `json:"column_name"` // 列名
|
||||
ColumnType string `json:"column_type"` // 列类型
|
||||
}
|
||||
|
||||
type DBValue struct {
|
||||
LastUserTime int64 `json:"last_user_time"`
|
||||
Value *gorm.DB `json:"value"`
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
package proto
|
||||
|
||||
import "time"
|
||||
|
||||
type FileUploadReq struct {
|
||||
UploadType string `json:"upload_type" form:"upload_type" binding:"required"`
|
||||
AuthType string `json:"auth_type" form:"auth_type"`
|
||||
Md5 string `json:"md5" form:"md5"` //文件md5值
|
||||
Type string `json:"type" form:"type"` //类型,im,avatar,file,config,config为系统文件
|
||||
}
|
||||
|
||||
type ConfigFileReq struct {
|
||||
ID int `json:"id" form:"id"`
|
||||
Type string `json:"type" form:"type"` //查询类型,one,all
|
||||
DelFile bool `json:"del_file"` //删除文件
|
||||
FileName string `json:"file_name" form:"file_name"`
|
||||
FilePath string `json:"file_path" form:"file_path"`
|
||||
Content string `json:"content" form:"content"`
|
||||
}
|
||||
|
||||
type AddConfigFileReq struct {
|
||||
FileName string `json:"file_name" form:"file_name" required:"true"`
|
||||
FilePath string `json:"file_path" form:"file_path" required:"true"`
|
||||
}
|
||||
type SearchOneConfigFileResp struct {
|
||||
ID uint `json:"id" form:"id"`
|
||||
CreatedAt time.Time `json:"created_at" form:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at" form:"updated_at"`
|
||||
FileName string `json:"file_name" form:"file_name"`
|
||||
FilePath string `json:"file_path" form:"file_path"`
|
||||
Content string `json:"content" form:"content"`
|
||||
}
|
||||
10
proto/im.go
10
proto/im.go
|
|
@ -1,5 +1,7 @@
|
|||
package proto
|
||||
|
||||
import "time"
|
||||
|
||||
type ImKeyReq struct {
|
||||
To_user_id int `json:"to_user_id" form:"to_user_id" binding:"required"`
|
||||
}
|
||||
|
|
@ -12,3 +14,11 @@ type Message struct {
|
|||
From_user_id int `json:"from_user_id"`
|
||||
Session string `json:"session"`
|
||||
}
|
||||
|
||||
// cid正在运行结构
|
||||
type CIDRunning struct {
|
||||
ID int `json:"id" form:"id"` //cid的id
|
||||
CID string `json:"cid" form:"cid"` //cid名称
|
||||
AuthID int `json:"auth_id" form:"auth_id"` //所属用户
|
||||
StartTime time.Time `json:"start_time" form:"start_time"` //开始时间
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
package proto
|
||||
|
||||
type GeneralResp struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
Data any `json:"data"`
|
||||
}
|
||||
|
||||
type CIDCallBackReq struct {
|
||||
Token string `json:"token" form:"token"`
|
||||
ID int `json:"id" form:"id"`
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
package proto
|
||||
|
||||
type GetMonitorDeviceStatus struct {
|
||||
ID string `json:"id" form:"id"` //设备编码
|
||||
Status string `json:"status" form:"status"` //设备状态
|
||||
Expire int `json:"expire" form:"expire"` //设备过期时间,及更新时间
|
||||
}
|
||||
|
|
@ -18,8 +18,9 @@ const (
|
|||
TokenParseError = 19 // Token解析错误
|
||||
|
||||
// 用户名密码相关错误码
|
||||
UsernameOrPasswordError = 6 // 用户名或密码错误
|
||||
UsernameExists = 7 // 用户名已存在
|
||||
UsernameOrPasswordError = 6 // 用户名或密码错误
|
||||
UsernameExists = 7 // 用户名已存在
|
||||
PermissionDenied = 21 // 权限不足
|
||||
|
||||
// Redis相关错误码
|
||||
RedisSetError = 8 // 设置redis错误
|
||||
|
|
@ -46,6 +47,7 @@ const (
|
|||
NoRedisPermissions = 51
|
||||
NoRunPermissions = 52
|
||||
NoDevicePermissions = 53
|
||||
NoPermission = 54
|
||||
|
||||
//消息错误码
|
||||
MsgSendFailed = 61 // 消息发送失败
|
||||
|
|
@ -59,4 +61,31 @@ const (
|
|||
NoUploadPermissions = 76 // 无上传权限
|
||||
DeleteFileFailed = 77 // 删除文件失败
|
||||
DeleteFileInfoFailed = 78 // 删除文件信息失败
|
||||
|
||||
DataFormatError = 80 // 数据格式错误
|
||||
|
||||
AddConfigFileFailed = 90 // 添加配置文件失败
|
||||
UpdateConfigFailed = 91 // 更新配置失败
|
||||
DeleteConfigFailed = 92 // 删除配置失败
|
||||
SearchConfigFileFailed = 93 // 获取配置失败
|
||||
|
||||
ShellCreateFailed = 100 // 创建shell失败
|
||||
ShellUpdateFailed = 101 // 更新shell失败
|
||||
ShellDeleteFailed = 102 // 删除shell失败
|
||||
ShellSearchFailed = 103 // 获取shell失败
|
||||
|
||||
//monitor部分错误码
|
||||
MonitorServerIDIsNull = 110 // 监控服务器ID为空
|
||||
MonitorServerIDNotFound = 111 // 监控服务器ID不存在
|
||||
|
||||
SigningKeyVersionIsTooOld = 200
|
||||
|
||||
//下面是数据库管理工具-错误状态码 100x
|
||||
DBMRunSQLFailed = 1001 // 执行SQL失败
|
||||
DBMCreateFailed = 1002 // 创建数据库管理失败
|
||||
DBMGetFailed = 1003 // 获取数据库管理信息失败`
|
||||
DBMUpdateFailed = 1004 // 更新数据库管理信息失败
|
||||
DBMDeleteFailed = 1005 // 删除数据库管理信息失败
|
||||
DBMRunSQLHistoryDeleteFailed = 1006 // 删除SQL运行历史失败
|
||||
DBMGetTableDescFailed = 1007 // 获取表描述信息失败
|
||||
)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,146 @@
|
|||
package proto
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type UpdateUserInfoReq struct {
|
||||
ID int `json:"id" form:"id"` //用户id
|
||||
Username string `json:"name" form:"name"` //用户名
|
||||
Age int `json:"age" form:"age"` //年龄
|
||||
Role string `json:"role" form:"role"` //角色
|
||||
Gender string `json:"gender" form:"gender"` //性别
|
||||
Redis bool `json:"redis" form:"redis"` //是否刷新redis
|
||||
Upload bool `json:"upload" form:"upload"` //是否上传头像
|
||||
VideoFunc bool `json:"video_func" form:"video_func"` //视频功能
|
||||
DeviceFunc bool `json:"device_func" form:"device_func"` //设备功能
|
||||
CIDFunc bool `json:"cid_func" form:"cid_func"` //持续集成功能
|
||||
Run bool `json:"run" form:"run"` //是否运行
|
||||
Avatar string `json:"avatar" form:"avatar"` //头像
|
||||
}
|
||||
|
||||
type CIDRUN struct {
|
||||
CID uint `json:"cid" form:"cid"` //持续集成ID,查找持续集成任务
|
||||
Curr int `json:"curr" form:"curr"` //当前剩余时间,每次执行减10s小于等于0则执行
|
||||
Every int `json:"every" form:"every"` //每隔多少秒执行一次,小于等于0表示不执行,时间粒度为10s
|
||||
}
|
||||
|
||||
// 用于执行函数,方法
|
||||
type CronInfo struct {
|
||||
Type int `json:"type" form:"type"` //类型编码,1日志清理(且只会有一个),其他待定,2从服务器同步数据
|
||||
Info string `json:"info" form:"info"` //信息
|
||||
Curr int `json:"curr" form:"curr"` //当前剩余时间,每次执行减10s小于等于0则执行
|
||||
Every int `json:"every" form:"every"` //每隔多少秒执行一次,小于等于0表示不执行,时间粒度为10s
|
||||
}
|
||||
|
||||
// 用户数据同步
|
||||
type UserSync struct {
|
||||
Update []UserAddOrUpdate `json:"update" form:"update"` //更新用户
|
||||
Add []UserAddOrUpdate `json:"add" form:"add"` //添加用户
|
||||
Delete []UserDelID `json:"delete" form:"delete"` //删除用户
|
||||
}
|
||||
|
||||
// 用户数据同步确认
|
||||
type UserSyncConfirm struct {
|
||||
Add []UserConfirmID `json:"add" form:"add"` //添加用户
|
||||
Update []UserConfirmID `json:"update" form:"update"` //更新用户
|
||||
Delete []UserConfirmID `json:"delete" form:"delete"` //删除用户
|
||||
}
|
||||
|
||||
type UserConfirmID struct {
|
||||
ID uint `json:"id" form:"id"` //用户id
|
||||
}
|
||||
|
||||
type UserDelID struct {
|
||||
ID uint `json:"ID" form:"ID"` //用户id
|
||||
}
|
||||
|
||||
type UserAddOrUpdate struct {
|
||||
ID uint `json:"ID" form:"ID"` //用户id
|
||||
CreatedAt time.Time `json:"CreatedAt" form:"CreatedAt"` //创建时间
|
||||
UpdatedAt time.Time `json:"UpdatedAt" form:"UpdatedAt"` //更新时间
|
||||
DeletedAt time.Time `json:"DeletedAt" form:"DeletedAt"` //删除时间
|
||||
Name string `json:"Name" form:"Name"` //用户名
|
||||
Age int `json:"Age" form:"Age"` //年龄
|
||||
Email string `json:"Email" form:"Email"` //邮箱
|
||||
Password string `json:"Password" form:"Password"` //密码
|
||||
Gender string `json:"Gender" form:"Gender"` //性别
|
||||
Role string `json:"Role" form:"Role"` //角色
|
||||
Redis bool `json:"Redis" form:"Redis"` //是否刷新redis
|
||||
Run bool `json:"Run" form:"Run"` //是否运行
|
||||
Upload bool `json:"Upload" form:"Upload"` //是否上传头像
|
||||
VideoFunc bool `json:"VideoFunc" form:"VideoFunc"` //视频功能
|
||||
DeviceFunc bool `json:"DeviceFunc" form:"DeviceFunc"`
|
||||
CIDFunc bool `json:"CIDFunc" form:"CIDFunc"`
|
||||
Avatar string `json:"Avatar" form:"Avatar"` //头像
|
||||
CreateTime string `json:"CreateTime" form:"CreateTime"`
|
||||
UpdateTime string `json:"UpdateTime" form:"UpdateTime"`
|
||||
}
|
||||
|
||||
// 数据同步请求
|
||||
type SyncUserReq struct {
|
||||
Token string `json:"token" form:"token"`
|
||||
Types int `json:"type" form:"type"` // 1为全量同步 2为增量同步
|
||||
Device string `json:"device" form:"device"`
|
||||
Confirm UserSyncConfirm `json:"confirm" form:"confirm"`
|
||||
}
|
||||
|
||||
// shell待执行
|
||||
type SyncUserShellReq struct {
|
||||
Token string `json:"token" form:"token"`
|
||||
Server string `json:"server" form:"server"`
|
||||
}
|
||||
|
||||
type UpdateShellReq struct {
|
||||
ID uint `json:"id"`
|
||||
ShellName string `json:"shell_name"`
|
||||
ShellContent string `json:"shell_content"`
|
||||
Server string `json:"server"`
|
||||
Status int `json:"status"`
|
||||
ShellResult string `json:"shell_result"`
|
||||
ShellRuntime float64 `json:"shell_runtime" form:"shell_runtime"` // 执行时间,单位秒
|
||||
}
|
||||
|
||||
// shell 执行结果返回
|
||||
type SyncUserShellResp struct {
|
||||
Token string `json:"token" form:"token"`
|
||||
Shells []UpdateShellReq `json:"shells" form:"shells"`
|
||||
}
|
||||
|
||||
type UpdateShellRespV2 struct {
|
||||
ID uint `json:"id" form:"id"`
|
||||
Status int `json:"status" form:"status"`
|
||||
}
|
||||
|
||||
type ResponseOAuth struct {
|
||||
ID uint `json:"id" form:"id"`
|
||||
Name string `json:"name" form:"name"`
|
||||
Email string `json:"email" form:"email"`
|
||||
Token string `json:"token" form:"token"`
|
||||
}
|
||||
|
||||
type SecretSyncSettings struct {
|
||||
Prev string `json:"prev"` // 前一个secret
|
||||
Curr string `json:"curr"` // 当前的secret
|
||||
Next string `json:"next"` // 下一个secret
|
||||
CurrExpectedExpiration int64 `json:"curr_expected_expiration"` // 当前密钥的预期过期时间戳
|
||||
PrevEndTimestamp int64 `json:"prev_end_timestamp"` // 前一个secret的结束时间戳
|
||||
CurrStartTimestamp int64 `json:"curr_start_timestamp"` // 当前secret的开始时间戳
|
||||
NextStartTimestamp int64 `json:"next_start_timestamp"` // 下一个secret的开始时间戳
|
||||
}
|
||||
|
||||
type SyncSystemConfigRequest struct {
|
||||
//时间戳
|
||||
Timestamp int64 `json:"timestamp" form:"timestamp"` // 时间戳
|
||||
//设备标识
|
||||
DeviceApp string `json:"device_app" form:"device_app"` // 设备标识
|
||||
//加密信息
|
||||
Sign string `json:"sign" form:"sign"` // 加密信息,app的secret加密后的值
|
||||
SecretKeyMd5 string `json:"secret_key_md5" form:"secret_key_md5"` // 密钥的MD5值,用于验证
|
||||
}
|
||||
|
||||
type RequestSyncSecretResp struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
Data string `json:"data"`
|
||||
}
|
||||
|
|
@ -0,0 +1,250 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"gorm.io/driver/mysql"
|
||||
"gorm.io/driver/postgres"
|
||||
"gorm.io/gorm"
|
||||
"strconv"
|
||||
"videoplayer/dao"
|
||||
"videoplayer/proto"
|
||||
"videoplayer/worker"
|
||||
)
|
||||
|
||||
func RunSQL(req *proto.RunSQLRequest) (*proto.SQLResult, error) {
|
||||
|
||||
dbmInfo, err := dao.FindDBManageByID(req.DB_ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if dbmInfo.UserID != req.UserID {
|
||||
return nil, errors.New("unauthorized access to the database management system")
|
||||
}
|
||||
db_, err := GetGORMDBObject(&dbmInfo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, err := dao.RunSQLWithOrder(req.SQL, db_)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// 记录执行历史
|
||||
history := &proto.SQLRunHistory{UserID: req.UserID, DB_ID: req.DB_ID, SQL: req.SQL, Status: 0}
|
||||
_, err = dao.CreateDBRunHistory(history)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &res, nil
|
||||
}
|
||||
|
||||
func GetGORMDBObject(dbmInfo *proto.DBManage) (db_ *gorm.DB, err error) {
|
||||
//dao.DBMMapRWMutex.RLock()
|
||||
if dao.DBMMap != nil {
|
||||
dbValue := dao.DBMMap[dbmInfo.ID]
|
||||
if dbValue != nil {
|
||||
dbValue.LastUserTime = worker.GetCurrentTimestamp()
|
||||
return dbValue.Value, nil
|
||||
}
|
||||
}
|
||||
//dao.DBMMapRWMutex.RUnlock()
|
||||
|
||||
switch dbmInfo.DB_Type {
|
||||
case proto.DB_TYPE_MYSQL: // MySQL
|
||||
dsn := dbmInfo.DB_User + ":" + dbmInfo.DB_Password + "@tcp(" + dbmInfo.DB_IP + ":" + strconv.Itoa(int(dbmInfo.DB_Port)) + ")/" + dbmInfo.DB_NAME + "?charset=utf8mb4&parseTime=True&loc=Local"
|
||||
db_, err = gorm.Open(mysql.Open(dsn), &gorm.Config{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case proto.DB_TYPE_POSTGRES: // PostgreSQL
|
||||
dsn := "host=" + dbmInfo.DB_IP + " user=" + dbmInfo.DB_User + " password=" + dbmInfo.DB_Password + " dbname=" + dbmInfo.DB_NAME + " port=" + strconv.Itoa(int(dbmInfo.DB_Port)) + " sslmode=disable TimeZone=Asia/Shanghai"
|
||||
|
||||
db_, err = gorm.Open(postgres.Open(dsn), &gorm.Config{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
default:
|
||||
err = errors.New("unsupported database type")
|
||||
}
|
||||
|
||||
dao.DBMMapRWMutex.Lock()
|
||||
var dbValue proto.DBValue
|
||||
dbValue.Value = db_
|
||||
dbValue.LastUserTime = worker.GetCurrentTimestamp()
|
||||
dao.DBMMap[dbmInfo.ID] = &dbValue
|
||||
dao.DBMMapRWMutex.Unlock()
|
||||
return db_, err
|
||||
}
|
||||
|
||||
func CreateDBManage(req *proto.CreateDBManageReq, userID uint) (proto.DBManage, error) {
|
||||
dbmInfo := proto.DBManage{
|
||||
UserID: userID,
|
||||
DB_IP: req.DB_IP,
|
||||
DB_Port: req.DB_Port,
|
||||
DB_NAME: req.DB_NAME,
|
||||
DB_User: req.DB_User,
|
||||
DB_Password: req.DB_Password,
|
||||
DB_Type: req.DB_Type,
|
||||
DB_Desc: req.DB_Desc,
|
||||
DB_STATUS: 0, // 初始状态为未连接
|
||||
}
|
||||
|
||||
id, err := dao.CreateDBManage(dbmInfo)
|
||||
if err != nil {
|
||||
return proto.DBManage{}, err
|
||||
}
|
||||
dbmInfo.ID = id
|
||||
return dbmInfo, nil
|
||||
}
|
||||
|
||||
func GetDBManageList(req *proto.GetDBManageReq, userID uint) ([]proto.DBManage, error) {
|
||||
var dbmList []proto.DBManage
|
||||
var err error
|
||||
|
||||
if req.GET_TYPE == 0 { // 获取自己的数据库管理
|
||||
dbmList, err = dao.FindDBManageByAuthID(userID)
|
||||
} else if req.GET_TYPE == 1 { // 管理员获取所有数据库管理
|
||||
user := GetUserByIDFromUserCenter(int(userID))
|
||||
if user.Role != "admin" {
|
||||
return nil, errors.New("unauthorized access, only admin can get all database management")
|
||||
}
|
||||
dbmList, err = dao.FindAllDBManage()
|
||||
} else {
|
||||
return nil, errors.New("invalid get type")
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dbmList, nil
|
||||
}
|
||||
|
||||
func GetSQLRunHistory(req *proto.GetSQLRunHistoryReq, userID int) ([]proto.SQLRunHistory, error) {
|
||||
var historyList []proto.SQLRunHistory
|
||||
var err error
|
||||
|
||||
if req.GET_TYPE == 0 { // 获取自己的SQL执行历史
|
||||
if req.DB_ID > 0 {
|
||||
historyList, err = dao.FindDBRunHistoryByAuthIDAndDbId(userID, req.DB_ID)
|
||||
} else {
|
||||
historyList, err = dao.FindDBRunHistoryByAuthID(userID)
|
||||
}
|
||||
} else if req.GET_TYPE == 1 { // 管理员获取所有SQL执行历史
|
||||
user := GetUserByIDFromUserCenter(userID)
|
||||
if user.Role != "admin" {
|
||||
return nil, errors.New("unauthorized access, only admin can get all SQL run history")
|
||||
}
|
||||
historyList, err = dao.FindAllSQLRunHistory()
|
||||
} else {
|
||||
return nil, errors.New("invalid get type")
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return historyList, nil
|
||||
}
|
||||
|
||||
func UpdateDBManage(req *proto.UpdateDBManageReq, userID int) (proto.DBManage, error) {
|
||||
dbmInfo, err := dao.FindDBManageByID(req.DB_ID)
|
||||
if err != nil {
|
||||
return proto.DBManage{}, err
|
||||
}
|
||||
if dbmInfo.UserID != uint(userID) && GetUserByIDFromUserCenter(userID).Role != "admin" {
|
||||
return proto.DBManage{}, errors.New("unauthorized access to the database management system")
|
||||
}
|
||||
dbmInfo.DB_IP = req.DB_IP
|
||||
dbmInfo.DB_Port = req.DB_Port
|
||||
dbmInfo.DB_NAME = req.DB_NAME
|
||||
dbmInfo.DB_User = req.DB_User
|
||||
dbmInfo.DB_Password = req.DB_Password
|
||||
dbmInfo.DB_Type = req.DB_Type
|
||||
dbmInfo.DB_Desc = req.DB_Desc
|
||||
|
||||
err = dao.UpdateDBManage(dbmInfo.ID, &dbmInfo)
|
||||
if err != nil {
|
||||
return proto.DBManage{}, err
|
||||
}
|
||||
return dbmInfo, nil
|
||||
}
|
||||
|
||||
func DeleteDBManage(req *proto.DeleteDBManageReq, userId int) error {
|
||||
user := GetUserByIDFromUserCenter(userId)
|
||||
if req.Del_Type == 0 && req.DB_ID > 0 {
|
||||
dbmInfo, err := dao.FindDBManageByID(req.DB_ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if dbmInfo.UserID != uint(req.UserID) && user.Role != "admin" {
|
||||
return errors.New("unauthorized access to the database management system")
|
||||
}
|
||||
err = dao.DeleteDBManageByID(req.DB_ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else if req.Del_Type == 1 && req.UserID > 0 {
|
||||
if req.UserID != uint(userId) && user.Role != "admin" {
|
||||
return errors.New("unauthorized access to delete all database management systems")
|
||||
}
|
||||
err := dao.DeleteDBManageByUserID(req.UserID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
return errors.New("invalid delete type or parameters")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeleteSQLRunHistory(req *proto.DeleteDBManageSQLHistoryReq, userId int) error {
|
||||
user := GetUserByIDFromUserCenter(userId)
|
||||
if req.Del_Type == 0 && req.History_ID > 0 {
|
||||
history, err := dao.FindDBRunHistoryByID(req.History_ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if history.UserID != uint(req.UserID) && user.Role != "admin" {
|
||||
return errors.New("unauthorized access to the SQL run history")
|
||||
}
|
||||
err = dao.DelSQLRunHistoryByID(req.History_ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else if req.Del_Type == 1 && req.UserID > 0 {
|
||||
if req.UserID != uint(userId) && user.Role != "admin" {
|
||||
return errors.New("unauthorized access to delete all SQL run history")
|
||||
}
|
||||
err := dao.DelSQLRunHistoryByAuthID(int(req.UserID))
|
||||
return err
|
||||
} else {
|
||||
return errors.New("invalid delete type or parameters")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetDBTableDesc(req *proto.GetDBTableDescReq, userId int) (*proto.SQLResult, error) {
|
||||
//dbmInfo, err := dao.FindDBManageByID(req.DB_ID)
|
||||
//if err != nil {`
|
||||
// return nil, err
|
||||
//}
|
||||
//if dbmInfo.UserID != uint(userId) && GetUserByIDFromUserCenter(userId).Role != "admin" {
|
||||
// return nil, errors.New("unauthorized access to the database management system")
|
||||
//}
|
||||
//db_, err := GetGORMDBObject(&dbmInfo)
|
||||
//if err != nil {
|
||||
// return nil, err
|
||||
//}
|
||||
//res, err := dao.GetDBTableDesc(db_, req.Table, req.GetType)
|
||||
//if err != nil {
|
||||
// return nil, err
|
||||
//}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func DelDBMMap() {
|
||||
dao.DBMMapRWMutex.Lock()
|
||||
cur := worker.GetCurrentTimestamp()
|
||||
for k, v := range dao.DBMMap {
|
||||
if (cur - v.LastUserTime) > proto.DBMMap_Max_Keep_Time {
|
||||
delete(dao.DBMMap, k) //删除
|
||||
}
|
||||
}
|
||||
dao.DBMMapRWMutex.Unlock()
|
||||
}
|
||||
|
|
@ -1,12 +1,17 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/google/uuid"
|
||||
"io"
|
||||
"mime/multipart"
|
||||
"os"
|
||||
"path"
|
||||
"regexp"
|
||||
"time"
|
||||
"videoplayer/dao"
|
||||
"videoplayer/proto"
|
||||
"videoplayer/worker"
|
||||
)
|
||||
|
|
@ -34,7 +39,6 @@ func SaveFile(c *gin.Context, file *multipart.FileHeader, uploadType string) (st
|
|||
//生成文件路径
|
||||
path_ := getFilePath(proto.FILE_BASE_DIR)
|
||||
filePath := path_ + "/" + fileStoreName
|
||||
|
||||
//保存文件
|
||||
if err := c.SaveUploadedFile(file, filePath); err != nil {
|
||||
return "", "", err
|
||||
|
|
@ -45,3 +49,171 @@ func SaveFile(c *gin.Context, file *multipart.FileHeader, uploadType string) (st
|
|||
|
||||
return path_, fileStoreName, nil
|
||||
}
|
||||
|
||||
func CalculateFileMd5(file io.Reader) string {
|
||||
hash := md5.New()
|
||||
if _, err := io.Copy(hash, file); err != nil {
|
||||
return ""
|
||||
}
|
||||
return fmt.Sprintf("%x", hash.Sum(nil))
|
||||
}
|
||||
|
||||
func CheckUploadRequestParameters(req *proto.FileUploadReq) error {
|
||||
var err error
|
||||
if req.AuthType == "" {
|
||||
err = fmt.Errorf("auth_type is empty")
|
||||
}
|
||||
if req.UploadType == "" {
|
||||
req.UploadType = "1"
|
||||
}
|
||||
if req.UploadType != "1" {
|
||||
req.UploadType = "2"
|
||||
}
|
||||
if proto.File_Type[req.Type] == 0 {
|
||||
err = fmt.Errorf("file type is invalid")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func CreateConfigFile(req *proto.AddConfigFileReq, userId int) error {
|
||||
var err error
|
||||
user := GetUserByIDWithCache(userId)
|
||||
if user.ID == 0 || user.Role != "admin" {
|
||||
err = fmt.Errorf("user not found or no permission")
|
||||
return err
|
||||
}
|
||||
if req.FileName == "" || req.FilePath == "" {
|
||||
err = fmt.Errorf("file name or file path is empty")
|
||||
return err
|
||||
}
|
||||
//查看系统中是否存在文件,不存在则创建
|
||||
file := req.FilePath + "/" + req.FileName
|
||||
//正则判断文件名是否合法
|
||||
pattern := `^/([^/:\*?]+/)*([^/:\*?]+)?$`
|
||||
reg := regexp.MustCompile(pattern)
|
||||
if reg.MatchString(file) == false {
|
||||
err = fmt.Errorf("file path is invalid")
|
||||
return err
|
||||
}
|
||||
_, fileErr := os.Stat(file)
|
||||
if fileErr != nil {
|
||||
//创建文件
|
||||
f, err2 := os.Create(file)
|
||||
if err2 != nil {
|
||||
err = err2
|
||||
return err
|
||||
}
|
||||
defer func(f *os.File) {
|
||||
err := f.Close()
|
||||
if err != nil {
|
||||
fmt.Println("Error closing file")
|
||||
}
|
||||
}(f)
|
||||
}
|
||||
//创建
|
||||
configFile := dao.ConfigFile{FilePath: req.FilePath, FileName: req.FileName, AuthID: userId}
|
||||
_, err3 := dao.CreateConfigFile(configFile)
|
||||
if err3 != nil {
|
||||
err = err3
|
||||
return err
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func DeleteConfigFile(req *proto.ConfigFileReq, userId int) error {
|
||||
var err error
|
||||
user := GetUserByIDWithCache(userId)
|
||||
if user.ID == 0 || user.Role != "admin" {
|
||||
err = fmt.Errorf("user not found or no permission")
|
||||
return err
|
||||
}
|
||||
//删除文件
|
||||
config_file := dao.FindConfigFileByID(req.ID, userId)
|
||||
if config_file.ID == 0 {
|
||||
err = fmt.Errorf("config file not found")
|
||||
return err
|
||||
}
|
||||
err = dao.DeleteConfigFileByID(req.ID)
|
||||
if req.DelFile {
|
||||
file := config_file.FilePath + "/" + config_file.FileName
|
||||
err = os.Remove(file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
//删除数据库记录
|
||||
return err
|
||||
}
|
||||
|
||||
type ConfigFileService struct {
|
||||
}
|
||||
|
||||
func (c *ConfigFileService) UpdateConfigFile(req *proto.ConfigFileReq, userId int) error {
|
||||
var err error
|
||||
user := GetUserByIDWithCache(userId)
|
||||
if user.ID == 0 || user.Role != "admin" {
|
||||
err = fmt.Errorf("user not found or no permission")
|
||||
return err
|
||||
}
|
||||
config_file := dao.FindConfigFileByID(req.ID, userId)
|
||||
if config_file.ID == 0 {
|
||||
err = fmt.Errorf("config file not found")
|
||||
return err
|
||||
}
|
||||
//修改文件名
|
||||
if req.FileName != "" {
|
||||
file := config_file.FilePath + "/" + config_file.FileName
|
||||
new_file := config_file.FilePath + "/" + req.FileName
|
||||
err = os.Rename(file, new_file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = dao.UpdateConfigFileByID(req.ID, dao.ConfigFile{FileName: req.FileName})
|
||||
}
|
||||
if req.Content != "" {
|
||||
file := config_file.FilePath + "/" + config_file.FileName
|
||||
f, err2 := os.OpenFile(file, os.O_WRONLY|os.O_TRUNC, 0644) //打开文件,清空文件内容,写入新内容,不存在则创建
|
||||
if err2 != nil {
|
||||
err = err2
|
||||
return err
|
||||
}
|
||||
defer func(f *os.File) {
|
||||
err3 := f.Close()
|
||||
if err3 != nil {
|
||||
fmt.Println("Error closing file")
|
||||
}
|
||||
}(f)
|
||||
_, err = f.WriteString(req.Content)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *ConfigFileService) SearchOneConfigFile(req *proto.ConfigFileReq, userId int) ([]proto.SearchOneConfigFileResp, error) {
|
||||
user := GetUserByIDWithCache(userId)
|
||||
if user.ID == 0 || user.Role != "admin" {
|
||||
return []proto.SearchOneConfigFileResp{}, fmt.Errorf("user not found or no permission")
|
||||
}
|
||||
config_file := dao.FindConfigFileByID(req.ID, userId)
|
||||
if config_file.ID == 0 {
|
||||
return []proto.SearchOneConfigFileResp{}, fmt.Errorf("config file not found")
|
||||
}
|
||||
file := config_file.FilePath + "/" + config_file.FileName
|
||||
content, err2 := os.ReadFile(file)
|
||||
if err2 != nil {
|
||||
return []proto.SearchOneConfigFileResp{}, err2
|
||||
}
|
||||
resp := []proto.SearchOneConfigFileResp{{ID: config_file.ID, FilePath: config_file.FilePath, FileName: config_file.FileName, Content: string(content), CreatedAt: config_file.CreatedAt, UpdatedAt: config_file.UpdatedAt}}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (c *ConfigFileService) SearchAllConfigFile(userId int) ([]dao.ConfigFile, error) {
|
||||
user := GetUserByIDWithCache(userId)
|
||||
if user.ID == 0 || user.Role != "admin" {
|
||||
return []dao.ConfigFile{}, fmt.Errorf("user not found or no permission")
|
||||
}
|
||||
config_files := dao.FindConfigFileByAuthID(userId)
|
||||
return config_files, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,38 +15,91 @@ func CreateGeneralMessageService(from_id, to_id, msg_type, group_id int, content
|
|||
var id uint
|
||||
switch msg_type {
|
||||
case proto.MSG_TYPE_SIMPLE:
|
||||
//判断是否是好友
|
||||
friend := dao.FindFriend(from_id, to_id)
|
||||
if len(friend) == 0 {
|
||||
return errors.New("未添加好友"), 0
|
||||
//判断是否是好友,判断是否存在缓存,不存在则设置缓存,存在则判断是否是好友
|
||||
if worker.IsContainKey("user_"+strconv.Itoa(from_id)+"_friends") == false {
|
||||
//设置好友缓存
|
||||
isSuccess := SetFriendCache(from_id)
|
||||
//设置失败,直接查询数据库
|
||||
if !isSuccess {
|
||||
friend := dao.FindFriend(from_id, to_id)
|
||||
if len(friend) == 0 {
|
||||
return errors.New("未添加好友"), 0
|
||||
}
|
||||
} else {
|
||||
//判断是否是好友-redis方式
|
||||
is_f := worker.IsContainSet("user_"+strconv.Itoa(from_id)+"_friends", strconv.Itoa(to_id))
|
||||
if !is_f {
|
||||
return errors.New("未添加好友"), 0
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//判断是否是好友-redis方式
|
||||
is_f := worker.IsContainSet("user_"+strconv.Itoa(from_id)+"_friends", strconv.Itoa(to_id))
|
||||
if !is_f {
|
||||
return errors.New("未添加好友"), 0
|
||||
}
|
||||
}
|
||||
|
||||
err, id = dao.CreateSimpleMessage(from_id, to_id, content)
|
||||
res := worker.GetRedis("user_" + strconv.Itoa(to_id) + "_status_v2")
|
||||
if res == "1" {
|
||||
//在线,存入redis
|
||||
worker.PushRedisListWithExpire("user_"+strconv.Itoa(to_id)+"_msg_ids", strconv.Itoa(int(id)), time.Second*300)
|
||||
//发布消息
|
||||
worker.Publish("user_"+strconv.Itoa(to_id)+"_msg_ids", strconv.Itoa(int(id)), time.Second*300)
|
||||
}
|
||||
//判断接收方是否是机器人
|
||||
id_str := strconv.Itoa(to_id)
|
||||
if worker.IsContainSet("robots_ids", id_str) == true {
|
||||
go SetRobotMsg(from_id, to_id, content)
|
||||
}
|
||||
|
||||
case proto.MSG_TYPE_GROUP:
|
||||
if from_id == 0 || group_id == 0 || content == "" {
|
||||
return errors.New("参数错误"), 0
|
||||
}
|
||||
//判断该用户是否在群里
|
||||
groupUser := dao.FindGroupUser(from_id, group_id)
|
||||
if len(groupUser) == 0 {
|
||||
return errors.New("用户不在群里"), 0
|
||||
key := "group_" + strconv.Itoa(group_id) + "_users"
|
||||
//判断是否在群里
|
||||
if worker.IsContainKey(key) == false {
|
||||
//设置群缓存
|
||||
isSuccess := SetGroupCache(group_id)
|
||||
//设置失败,直接查询数据库
|
||||
if !isSuccess {
|
||||
groupUser := dao.FindGroupUser(from_id, group_id)
|
||||
if len(groupUser) == 0 {
|
||||
return errors.New("用户不在群里"), 0
|
||||
}
|
||||
} else {
|
||||
//判断该用户是否在群里-redis方式
|
||||
is_g := worker.IsContainSet("group_"+strconv.Itoa(group_id)+"_users", strconv.Itoa(from_id))
|
||||
if !is_g {
|
||||
return errors.New("用户不在群里"), 0
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//判断该用户是否在群里-redis方式
|
||||
is_g := worker.IsContainSet("group_"+strconv.Itoa(group_id)+"_users", strconv.Itoa(from_id))
|
||||
if !is_g {
|
||||
return errors.New("用户不在群里"), 0
|
||||
}
|
||||
}
|
||||
|
||||
err, id = dao.CreateGeneralMessage(from_id, to_id, msg_type, 0, group_id, content)
|
||||
//获取群里的用户
|
||||
users := dao.FindGroupUsers(group_id)
|
||||
for _, user := range users {
|
||||
if user.UserID == from_id {
|
||||
//user_ids := worker.GetRedisSetMembers("group_" + strconv.Itoa(group_id) + "_users")
|
||||
//在线的用户群id
|
||||
online_user_ids := worker.GetRedisSetIntersect("im2_online_users_set", "group_"+strconv.Itoa(group_id)+"_users")
|
||||
//users := dao.FindGroupUsers(group_id)
|
||||
for _, user_id := range online_user_ids {
|
||||
//判断是否是自己,不是则存入redis
|
||||
id_, _ := strconv.Atoi(user_id)
|
||||
if id_ == from_id {
|
||||
continue
|
||||
}
|
||||
res := worker.GetRedis("user_" + strconv.Itoa(user.UserID) + "_status_v2")
|
||||
if res == "1" {
|
||||
//在线,存入redis
|
||||
worker.PushRedisListWithExpire("user_"+strconv.Itoa(user.UserID)+"_msg_ids", strconv.Itoa(int(id)), time.Second*300)
|
||||
}
|
||||
//在线,存入redis
|
||||
worker.PushRedisListWithExpire("user_"+user_id+"_msg_ids", strconv.Itoa(int(id)), time.Second*300)
|
||||
//发布消息
|
||||
worker.Publish("user_"+user_id+"_msg_ids", strconv.Itoa(int(id)), time.Second*300)
|
||||
}
|
||||
case 3:
|
||||
//user := dao.FindUserByID(to_id)
|
||||
|
|
@ -64,6 +117,7 @@ func CreateGeneralMessageService(from_id, to_id, msg_type, group_id int, content
|
|||
return errors.New("已有请求"), res[0].ID
|
||||
}
|
||||
err, id = dao.CreateGeneralMessage(from_id, to_id, msg_type, 0, group_id, content)
|
||||
|
||||
case proto.MSG_TYPE_GROUP_ADD:
|
||||
//加入群聊请求
|
||||
//判断是否在群里
|
||||
|
|
@ -91,6 +145,13 @@ func CreateGeneralMessageService(from_id, to_id, msg_type, group_id int, content
|
|||
return errors.New("已在群里"), 0
|
||||
}
|
||||
err, id = dao.JoinGroup(group_id, to_id)
|
||||
if err == nil {
|
||||
//设置群缓存,如果存在缓存则加入
|
||||
if worker.IsContainKey("group_"+strconv.Itoa(group_id)+"_users") == true {
|
||||
//将用户加入群缓存
|
||||
worker.SetRedisSetAdd("group_"+strconv.Itoa(group_id)+"_users", strconv.Itoa(to_id))
|
||||
}
|
||||
}
|
||||
default:
|
||||
// 未知消息类型
|
||||
err = errors.New("unknown message type")
|
||||
|
|
@ -130,7 +191,17 @@ func AddFriendService(id, from_user_id, to_user_id int) error {
|
|||
return errors.New("already a friend")
|
||||
}
|
||||
dao.UpdateMessageStatus(res[0].ID, 1)
|
||||
return dao.AddFriend(from_user_id, to_user_id)
|
||||
res2 := dao.AddFriend(from_user_id, to_user_id)
|
||||
if res2 == nil {
|
||||
//设置好友缓存
|
||||
if worker.IsContainKey("user_"+strconv.Itoa(from_user_id)+"_friends") == true {
|
||||
worker.SetRedisSetAdd("user_"+strconv.Itoa(from_user_id)+"_friends", strconv.Itoa(to_user_id))
|
||||
}
|
||||
if worker.IsContainKey("user_"+strconv.Itoa(to_user_id)+"_friends") == true {
|
||||
worker.SetRedisSetAdd("user_"+strconv.Itoa(to_user_id)+"_friends", strconv.Itoa(from_user_id))
|
||||
}
|
||||
}
|
||||
return res2
|
||||
} else if res[0].ToUserID == from_user_id && res[0].GroupID == to_user_id {
|
||||
//加入群聊
|
||||
//查看是否已经加入
|
||||
|
|
@ -149,6 +220,21 @@ func AddFriendService(id, from_user_id, to_user_id int) error {
|
|||
}
|
||||
}
|
||||
|
||||
func RejectFriendService(id, from_user_id, to_user_id int) error {
|
||||
// 业务逻辑
|
||||
res := dao.FindMessageByID(uint(id))
|
||||
if len(res) == 0 {
|
||||
return errors.New("no such message")
|
||||
}
|
||||
if res[0].FromUserID == to_user_id && res[0].ToUserID == from_user_id {
|
||||
dao.UpdateMessageStatus(res[0].ID, 1) // 拒绝,设为已读
|
||||
return nil
|
||||
} else {
|
||||
return errors.New("no such message,cannot reject friend")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// CreateGroup 创建群聊
|
||||
// groupName 群聊名称
|
||||
// groupInfo 群聊信息
|
||||
|
|
@ -176,6 +262,13 @@ func GetFriendList(user_id int) FGRet {
|
|||
return fg
|
||||
}
|
||||
|
||||
func UpdateGroupService(group_id int, group_name, group_info, group_type, group_icon string, user_id int) error {
|
||||
//更新群聊
|
||||
err := dao.UpdateGroup(group_id, group_name, group_info, group_type, group_icon, user_id)
|
||||
return err
|
||||
|
||||
}
|
||||
|
||||
func GetFriendRequest(user_id int) []dao.FriendRequest {
|
||||
//获取好友请求
|
||||
users := dao.GetFriendRequest(user_id)
|
||||
|
|
@ -185,12 +278,20 @@ func GetFriendRequest(user_id int) []dao.FriendRequest {
|
|||
func DelFriendService(user_id, friend_id int) error {
|
||||
//删除好友
|
||||
err := dao.DeleteFriend(user_id, friend_id)
|
||||
//删除好友缓存
|
||||
if err == nil && worker.IsContainKey("user_"+strconv.Itoa(user_id)+"_friends") == true {
|
||||
worker.SetRedisSetRemove("user_"+strconv.Itoa(user_id)+"_friends", strconv.Itoa(friend_id))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func QuitGroupService(user_id, group_id int) error {
|
||||
//退出群聊
|
||||
err := dao.QuitGroup(group_id, user_id)
|
||||
//删除群缓存
|
||||
if err == nil && worker.IsContainKey("group_"+strconv.Itoa(group_id)+"_users") == true {
|
||||
worker.SetRedisSetRemove("group_"+strconv.Itoa(group_id)+"_users", strconv.Itoa(user_id))
|
||||
}
|
||||
return err
|
||||
}
|
||||
func DelGroupService(user_id, group_id int) error {
|
||||
|
|
@ -226,8 +327,92 @@ func GetGroupByNameLike(name string) []dao.Group {
|
|||
return groups
|
||||
}
|
||||
|
||||
func GetGroupRequestUsers(user_id int) []dao.FriendRequest {
|
||||
func GetGroupRequestUsers(user_id int) []dao.GroupRequestUsers {
|
||||
//获取群聊请求
|
||||
users := dao.GetGroupRequestUsers(user_id)
|
||||
return users
|
||||
}
|
||||
|
||||
// 设置用户朋友关系缓存
|
||||
func SetFriendCache(user_id int) bool {
|
||||
//获取好友id
|
||||
friends := dao.FindFriendsIDs(user_id)
|
||||
var ids []string
|
||||
for _, friend := range friends {
|
||||
ids = append(ids, strconv.Itoa(friend.FriendID))
|
||||
}
|
||||
res := worker.SetRedisSet("user_"+strconv.Itoa(user_id)+"_friends", ids, time.Hour*12)
|
||||
return res
|
||||
}
|
||||
|
||||
// 设置用户群关系缓存
|
||||
func SetGroupCache(group_id int) bool {
|
||||
//获取好友id
|
||||
users := dao.FindGroupUsers(group_id)
|
||||
var ids []string
|
||||
for _, user := range users {
|
||||
ids = append(ids, strconv.Itoa(user.UserID))
|
||||
}
|
||||
res := worker.SetRedisSet("group_"+strconv.Itoa(group_id)+"_users", ids, time.Hour*12)
|
||||
return res
|
||||
}
|
||||
|
||||
// 设置机器人返回消息
|
||||
func SetRobotMsg(person_id, robot_id int, msg string) {
|
||||
//发送
|
||||
url := "http://localhost:11434/api/generate"
|
||||
//body := map[string]interface{}{
|
||||
// "model": "qwen2.5:0.5b",
|
||||
// "prompt": msg,
|
||||
// "stream": false,
|
||||
//}
|
||||
//body_str, _ := json.Marshal(body)
|
||||
|
||||
data, err := worker.GenerateCompletion(url, msg, "qwen2.5:0.5b")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
//解析返回数据
|
||||
msg_res_content := data["response"].(string)
|
||||
//存入数据库,及robot_id为发送者,person_id为接收者
|
||||
err, _ = CreateGeneralMessageService(robot_id, person_id, proto.MSG_TYPE_SIMPLE, 0, msg_res_content)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 同意用户加入群聊
|
||||
func JoinGroupService(im_id, cid, user_id, group_id int) error {
|
||||
|
||||
group := dao.FindGroup(group_id)
|
||||
if len(group) == 0 {
|
||||
return errors.New("no such group")
|
||||
}
|
||||
if group[0].AuthID != cid {
|
||||
return errors.New("no permission")
|
||||
}
|
||||
|
||||
//判断是否在群里
|
||||
groupUser := dao.FindGroupUser(user_id, group_id)
|
||||
if len(groupUser) > 0 {
|
||||
return errors.New("已在群里")
|
||||
}
|
||||
err, _ := dao.JoinGroup(group_id, user_id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = dao.UpdateMessageStatus(uint(im_id), 1)
|
||||
return err
|
||||
}
|
||||
|
||||
func RejectGroupService(im_id, cid, user_id, group_id int) error {
|
||||
group := dao.FindGroup(group_id)
|
||||
if len(group) == 0 {
|
||||
return errors.New("no such group")
|
||||
}
|
||||
if group[0].AuthID != cid {
|
||||
return errors.New("no permission")
|
||||
}
|
||||
err := dao.UpdateMessageStatus(uint(im_id), 1) // 拒绝,设为已读
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,142 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"log"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
"videoplayer/dao"
|
||||
"videoplayer/proto"
|
||||
"videoplayer/worker"
|
||||
)
|
||||
|
||||
func CreateShell(shellName, shellContent, server string, uid int) uint {
|
||||
id := dao.CreateShell(shellName, shellContent, server, uint(uid))
|
||||
return id
|
||||
}
|
||||
|
||||
func FindShellByAuthID(id int) []dao.Shell {
|
||||
return dao.FindShellByAuthID(id)
|
||||
}
|
||||
|
||||
func DeleteShellByID(id, authId uint) bool {
|
||||
user := GetUserByIDFromUserCenter(int(authId))
|
||||
if user.Role == "admin" {
|
||||
return dao.DeleteShellByIDV2(id)
|
||||
}
|
||||
return dao.DeleteShellByID(id, authId)
|
||||
}
|
||||
|
||||
func UpdateShellByID(id, authId uint, shellName, shellContent, server string, status int, shellResult string) bool {
|
||||
return dao.UpdateShellByID(id, authId, shellName, shellContent, status, shellResult, 0, 0)
|
||||
}
|
||||
|
||||
func UpdateShellByIDV2(id, authId uint, shellName, shellContent, server string, status int, shellResult string, shellRuntime float64) bool {
|
||||
//查看shell是否存在
|
||||
pd := dao.FindShellByID(id, authId)
|
||||
if len(pd) < 1 && pd[0].ID == 0 {
|
||||
return false
|
||||
}
|
||||
shell := pd[0]
|
||||
//如果状态为2,3转为0,1是不允许的,为了防止出现1确认包阻塞问题
|
||||
if (shell.Status == 2 || shell.Status == 3) && (status == 0 || status == 1) {
|
||||
log.Println("UpdateShellByIDV2: status change from 2/3 to 0/1 is not allowed, shell id:", id)
|
||||
return false
|
||||
}
|
||||
var elapsed float64 //持续时间
|
||||
if (shell.Status == 0 || shell.Status == 1) && (status == 2 || status == 3) { //如果状态为执行中,且新更新时间状态为2或3,则获取持续时间
|
||||
elapsed = time.Since(shell.CreatedAt).Seconds()
|
||||
}
|
||||
return dao.UpdateShellByID(id, authId, shellName, shellContent, status, shellResult, shellRuntime, elapsed)
|
||||
}
|
||||
|
||||
func FindShellWillRunByServer(server string, uid int) ([]dao.Shell, error) {
|
||||
var shells []dao.Shell
|
||||
var err error
|
||||
if server == "" {
|
||||
//err设置为server为空
|
||||
err = errors.New("server is empty")
|
||||
return shells, err
|
||||
}
|
||||
shells = dao.FindShellWillRunByServer(server, uint(uid))
|
||||
//设置状态为执行中
|
||||
for _, v := range shells {
|
||||
dao.UpdateShellByID(v.ID, uint(uid), v.ShellName, v.ShellContent, v.Status+1, v.ShellResult, 0, 0) //将状态设置为执行中
|
||||
}
|
||||
return shells, err
|
||||
}
|
||||
|
||||
// 从服务器定时获取shell、执行并返回结果
|
||||
func ShellWillRunFromServer() {
|
||||
shells, err := GetShellWillRunFromMaster(proto.Config.SERVER_NAME)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var resp []proto.UpdateShellReq
|
||||
|
||||
for _, v := range shells {
|
||||
//执行shell脚本,go执行命令
|
||||
start := time.Now()
|
||||
res, err2 := RunShell(v.ShellContent)
|
||||
//执行时间,转成秒
|
||||
shellRuntime := time.Since(start).Seconds()
|
||||
if err2 != "" {
|
||||
resp = append(resp, proto.UpdateShellReq{ID: v.ID, Server: v.Server, Status: 3, ShellResult: "err:" + err2 + "\nresult:" + res, ShellRuntime: shellRuntime}) //执行出错
|
||||
} else {
|
||||
resp = append(resp, proto.UpdateShellReq{ID: v.ID, Server: v.Server, Status: 2, ShellResult: res, ShellRuntime: shellRuntime}) //执行成功
|
||||
}
|
||||
}
|
||||
if len(resp) == 0 {
|
||||
return
|
||||
}
|
||||
//返回执行结果
|
||||
url := "https://" + proto.Config.MASTER_SERVER_DOMAIN + "/shell/update?super_id=1"
|
||||
var req proto.SyncUserShellResp
|
||||
req.Token = worker.GetRedisSetMembers("super_permission_tokens")[0]
|
||||
req.Shells = resp
|
||||
resp_data, err := worker.SyncDataFromMasterShellReq3(url, req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
//更新执行结果
|
||||
for _, v := range resp_data {
|
||||
if v.Status < 0 {
|
||||
log.Fatalln("update shell failed:", v.ID, v.Status)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 从服务器从主服务器获取待执行的shell
|
||||
func GetShellWillRunFromMaster(server string) ([]dao.Shell, error) {
|
||||
master := proto.Config.MASTER_SERVER_DOMAIN
|
||||
//发起请求获取待执行的shell
|
||||
url := "https://" + master + "/shell/server_will_run_list?super_id=1"
|
||||
var req proto.SyncUserShellReq
|
||||
req.Server = server
|
||||
superPermissions := worker.GetRedisSetMembers("super_permission_tokens")
|
||||
if len(superPermissions) == 0 {
|
||||
log.Println("get shell will run from master error: no super permission tokens found, please check the configuration or redis!")
|
||||
return nil, errors.New("no super permission tokens found")
|
||||
}
|
||||
req.Token = superPermissions[0]
|
||||
shells, err := worker.SyncDataFromMasterShellReq2(url, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return shells, nil
|
||||
}
|
||||
|
||||
func RunShell(script string) (res, err string) {
|
||||
cmd := exec.Command("/bin/bash", "-c", script)
|
||||
// 使用bytes.Buffer捕获输出
|
||||
var out bytes.Buffer
|
||||
cmd.Stdout = &out
|
||||
err3 := cmd.Run()
|
||||
err3_info := ""
|
||||
if err3 != nil {
|
||||
err3_info = err3.Error()
|
||||
}
|
||||
return strings.TrimSpace(out.String()), err3_info
|
||||
}
|
||||
|
|
@ -1,6 +1,12 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"time"
|
||||
"videoplayer/proto"
|
||||
"videoplayer/worker"
|
||||
|
|
@ -68,3 +74,279 @@ func GetToolRedis(key string) (code int, message string) {
|
|||
return proto.SuccessCode, val
|
||||
}
|
||||
}
|
||||
|
||||
func GetAllRedis() (code int, msg string, data []worker.RedisInfo) {
|
||||
data, err := worker.GetAllRedisInfo()
|
||||
if err != nil {
|
||||
return proto.OperationFailed, err.Error(), nil
|
||||
}
|
||||
return proto.SuccessCode, "success", data
|
||||
}
|
||||
|
||||
func SendEmail(email, subject, body string) {
|
||||
//捕获异常
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
fmt.Errorf("tool send mail error: %s", err)
|
||||
}
|
||||
}()
|
||||
// TODO
|
||||
// 发送邮件
|
||||
// 邮件内容
|
||||
// 邮件标题
|
||||
// 收件人
|
||||
// 发送邮件
|
||||
// 发送邮件通知
|
||||
// 发送邮件通知
|
||||
var em worker.MyEmail
|
||||
em.SmtpPassword = "nihzazdkmucnbhid"
|
||||
em.SmtpHost = "pop.qq.com:587"
|
||||
em.SmtpUserName = "354425203@qq.com"
|
||||
em.SmtpPort = 587
|
||||
em.ImapPort = 993
|
||||
err := em.Send(subject, body, []string{email})
|
||||
if err != nil {
|
||||
fmt.Println("send mail error:", err)
|
||||
}
|
||||
}
|
||||
|
||||
// 地址校验
|
||||
func CheckEmail(email string) bool {
|
||||
//正则表达式判断是否是邮箱
|
||||
pattern := `^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(.[a-zA-Z0-9_-])+$`
|
||||
reg := regexp.MustCompile(pattern)
|
||||
return reg.MatchString(email)
|
||||
}
|
||||
|
||||
// 获取监控设备及状态
|
||||
func GetMonitorDeviceListWithStatus(userId int) ([]proto.GetMonitorDeviceStatus, error) {
|
||||
var deviceStatus []proto.GetMonitorDeviceStatus
|
||||
user := GetUserByIDFromUserCenter(userId)
|
||||
if user.Role != "admin" {
|
||||
return deviceStatus, errors.New("user is not admin, can not get monitor device list")
|
||||
} else {
|
||||
devices := worker.GetRedisSetMembers(proto.Config.MONITOR_SERVER_TOKEN)
|
||||
for _, device := range devices {
|
||||
status, expireIn := worker.GetRedisWithExpire("monitor_" + device)
|
||||
var deviceInfo proto.GetMonitorDeviceStatus
|
||||
deviceInfo.ID = device
|
||||
deviceInfo.Expire = expireIn
|
||||
if status == "" {
|
||||
deviceInfo.Status = "offline"
|
||||
} else {
|
||||
deviceInfo.Status = status
|
||||
}
|
||||
deviceStatus = append(deviceStatus, deviceInfo)
|
||||
}
|
||||
}
|
||||
return deviceStatus, nil
|
||||
}
|
||||
|
||||
func UpdateMonitorDeviceListWithStatus(userId int, deviceReq []proto.GetMonitorDeviceStatus) error {
|
||||
user := GetUserByIDFromUserCenter(userId)
|
||||
var err error
|
||||
if user.Role != "admin" {
|
||||
err = errors.New("user is not admin, can not update monitor device list")
|
||||
return err
|
||||
} else {
|
||||
// 更新监控设备状态.如果在集合中则添加,不在则添加到集合中
|
||||
devices := worker.GetRedisSetMembers(proto.Config.MONITOR_SERVER_TOKEN)
|
||||
deviceMap := make(map[string]bool, len(devices))
|
||||
for _, device := range devices {
|
||||
deviceMap[device] = true
|
||||
}
|
||||
for _, device := range deviceReq {
|
||||
if _, ok := deviceMap[device.ID]; ok {
|
||||
// 如果设备在集合中,则更新状态
|
||||
worker.SetRedisWithExpire("monitor_"+device.ID, device.Status, time.Duration(device.Expire)*time.Second)
|
||||
} else {
|
||||
worker.SetRedisSetAdd(proto.Config.MONITOR_SERVER_TOKEN, device.ID)
|
||||
worker.SetRedisWithExpire("monitor_"+device.ID, device.Status, time.Duration(device.Expire)*time.Second)
|
||||
}
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func DelMonitorDeviceListWithStatus(userId int, deviceReq []proto.GetMonitorDeviceStatus) ([]proto.GetMonitorDeviceStatus, error) {
|
||||
user := GetUserByIDFromUserCenter(userId)
|
||||
var err error
|
||||
var delDevices []proto.GetMonitorDeviceStatus
|
||||
if user.Role != "admin" {
|
||||
err = errors.New("user is not admin, can not update monitor device list")
|
||||
return delDevices, err
|
||||
} else {
|
||||
for _, device := range deviceReq {
|
||||
if worker.IsContainSet(proto.Config.MONITOR_SERVER_TOKEN, device.ID) {
|
||||
// 如果设备在集合中,则删除状态
|
||||
worker.DelRedis("monitor_" + device.ID)
|
||||
worker.SetRedisSetRemove(proto.Config.MONITOR_SERVER_TOKEN, device.ID)
|
||||
delDevices = append(delDevices, device)
|
||||
}
|
||||
}
|
||||
}
|
||||
return delDevices, err
|
||||
}
|
||||
|
||||
// 更新token密钥
|
||||
func SyncTokenSecretFromUserCenter() {
|
||||
secretSettings, err := GetTokenSecretFromUserCenter()
|
||||
if err != nil {
|
||||
log.Println("SyncTokenSecretFromUserCenter error:", err)
|
||||
return
|
||||
}
|
||||
//写入redis
|
||||
secretSettingsBytes, err2 := json.Marshal(secretSettings)
|
||||
if err2 != nil {
|
||||
log.Println("SyncTokenSecretFromUserCenter json marshal error:", err2)
|
||||
return
|
||||
}
|
||||
if proto.SyncSecretReqLog%100 == 0 {
|
||||
log.Println("SyncTokenSecretFromUserCenter req data:", string(secretSettingsBytes))
|
||||
}
|
||||
worker.SetRedis("secret_sync_settings", string(secretSettingsBytes)) //将密钥信息存入redis
|
||||
|
||||
if secretSettings.Curr != "" && secretSettings.Curr != proto.Config.TOKEN_SECRET && secretSettings.Next == "" { //如果当前密钥不为空且不等于配置文件中的密钥,并且下一个密钥为空,则需要更新配置文件中的密钥
|
||||
log.Printf("SyncTokenSecretFromUserCenter current secret is not equal to config secret, current: %s, config: %s\n", secretSettings.Curr, proto.Config.TOKEN_SECRET)
|
||||
//如果当前密钥与配置文件中的密钥不一致,则需要更新配置文件中的密钥
|
||||
proto.SigningKeyRWLock.Lock()
|
||||
proto.SigningKey = []byte(secretSettings.Curr)
|
||||
proto.Config.TOKEN_SECRET = secretSettings.Curr
|
||||
proto.SigningKeyRWLock.Unlock()
|
||||
proto.SigningKeyIsValid = true
|
||||
//配置写回文件
|
||||
go proto.WriteConfigToFile()
|
||||
log.Println("SyncTokenSecretFromUserCenter current secret updated successfully")
|
||||
}
|
||||
|
||||
if secretSettings.Next == "" {
|
||||
log.Println("SyncTokenSecretFromUserCenter secret is empty")
|
||||
} else if proto.SyncSecretReqLog%100 == 0 {
|
||||
go SetNextSecretToCurrent(*secretSettings) //异步设置下一个密钥为当前密钥
|
||||
}
|
||||
|
||||
proto.SyncSecretReqLog++ //记录同步密钥请求次数
|
||||
}
|
||||
func SetNextSecretToCurrent(secret_copy proto.SecretSyncSettings) {
|
||||
var secret_sync_settings proto.SecretSyncSettings
|
||||
redisKey := "secret_sync_settings"
|
||||
settingsStr := worker.GetRedis(redisKey)
|
||||
err := json.Unmarshal([]byte(settingsStr), &secret_sync_settings)
|
||||
if err != nil {
|
||||
log.Println("Error decoding secret sync settings:", err)
|
||||
} else {
|
||||
//如果当前密钥的下一个密钥与传入的密钥不一致,则不进行设置
|
||||
if secret_copy.Next != secret_sync_settings.Next {
|
||||
return
|
||||
}
|
||||
//获取需要等待时间
|
||||
waitTime := secret_sync_settings.NextStartTimestamp - worker.GetCurrentTimestamp()
|
||||
if waitTime > 0 {
|
||||
log.Printf("Waiting for %d seconds before setting the next secret as current secret\n", waitTime)
|
||||
time.Sleep(time.Duration(waitTime) * time.Second) //等待时间
|
||||
} else {
|
||||
log.Println("No need to wait, setting the next secret as current secret immediately")
|
||||
}
|
||||
//设置下一个密钥为当前密钥
|
||||
secret_sync_settings.Prev = secret_sync_settings.Curr
|
||||
secret_sync_settings.PrevEndTimestamp = worker.GetCurrentTimestamp()
|
||||
secret_sync_settings.Curr = secret_sync_settings.Next
|
||||
secret_sync_settings.Next = ""
|
||||
secret_sync_settings.CurrStartTimestamp = secret_sync_settings.PrevEndTimestamp
|
||||
proto.SigningKeyIsValid = true
|
||||
|
||||
//设置当前程序的密钥
|
||||
//获取写锁
|
||||
proto.SigningKeyRWLock.Lock()
|
||||
defer proto.SigningKeyRWLock.Unlock()
|
||||
proto.SigningKey = []byte(secret_sync_settings.Curr)
|
||||
|
||||
proto.Config.TOKEN_SECRET = secret_sync_settings.Curr
|
||||
//配置写回文件
|
||||
go proto.WriteConfigToFile()
|
||||
}
|
||||
settinsStr, err2 := json.Marshal(secret_sync_settings)
|
||||
if err2 != nil {
|
||||
log.Println("Error encoding set secret sync settings:", err2)
|
||||
return
|
||||
}
|
||||
worker.SetRedis(redisKey, string(settinsStr)) //将当前的密钥信息存入redis
|
||||
}
|
||||
|
||||
// 获取token密钥请求
|
||||
func GetTokenSecretFromUserCenter() (*proto.SecretSyncSettings, error) {
|
||||
url := "https://uc.ljsea.top/tool/sync_system_config"
|
||||
var req proto.SyncSystemConfigRequest
|
||||
proto.SigningKeyRWLock.Lock()
|
||||
defer proto.SigningKeyRWLock.Unlock()
|
||||
req.SecretKeyMd5 = worker.GenerateMD5(string(proto.SigningKey))
|
||||
req.DeviceApp = proto.Config.APP_ID
|
||||
req.Timestamp = worker.GetCurrentTimestamp()
|
||||
req.Sign = worker.GenerateMD5(req.SecretKeyMd5 + req.DeviceApp + strconv.FormatInt(req.Timestamp, 10))
|
||||
reqBytes, err2 := json.Marshal(req)
|
||||
if err2 != nil {
|
||||
log.Println("GetTokenSecretFromUserCenter json marshal error:", err2)
|
||||
return nil, err2
|
||||
}
|
||||
err, resp := worker.DoPostRequestJSON(url, reqBytes, nil)
|
||||
if err != nil {
|
||||
log.Println("GetTokenSecretFromUserCenter post request error:", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var respObject proto.RequestSyncSecretResp
|
||||
err = json.Unmarshal(resp, &respObject)
|
||||
if err != nil {
|
||||
log.Println("GetTokenSecretFromUserCenter json unmarshal error:", err)
|
||||
return nil, err
|
||||
}
|
||||
if respObject.Code != 0 {
|
||||
if respObject.Code == proto.SigningKeyVersionIsTooOld {
|
||||
proto.SigningKeyIsValid = false //设置当前密钥无效
|
||||
}
|
||||
log.Println("GetTokenSecretFromUserCenter error code:", respObject.Code, "\t, message:", respObject.Message)
|
||||
return nil, fmt.Errorf("GetTokenSecretFromUserCenter error code: %d, message: %s", respObject.Code, respObject.Message)
|
||||
}
|
||||
|
||||
//对称加密密钥。通过密钥加 secret_key 取md5
|
||||
secretKeyMd5 := worker.GenerateMD5(proto.Config.TOKEN_SECRET + "_sync_secret")
|
||||
|
||||
//解密返回数据
|
||||
dataContent, err2 := worker.AESDecrypt(respObject.Data, []byte(secretKeyMd5))
|
||||
if err2 != nil {
|
||||
log.Println("GetTokenSecretFromUserCenter aes decrypt error:", err2, "\t, secret:", proto.Config.TOKEN_SECRET, "\t, secretKey:", secretKeyMd5, "\t, data:", respObject.Data)
|
||||
return nil, err2
|
||||
}
|
||||
var secretResp proto.SecretSyncSettings
|
||||
err = json.Unmarshal(dataContent, &secretResp)
|
||||
if err != nil {
|
||||
log.Println("GetTokenSecretFromUserCenter json unmarshal error:", err)
|
||||
return nil, err
|
||||
}
|
||||
return &secretResp, nil
|
||||
}
|
||||
|
||||
// 获取cid正在运行
|
||||
func GetCIDRunningList(user_id int, req_type int) ([]proto.CIDRunning, error) {
|
||||
var err error
|
||||
var resp []proto.CIDRunning
|
||||
if req_type == 0 {
|
||||
proto.CID_RunningMutex.RLock()
|
||||
resp = proto.CID_Running_Map[user_id]
|
||||
proto.CID_RunningMutex.RUnlock()
|
||||
} else if req_type == 1 {
|
||||
user := GetUserByIDFromUserCenter(user_id)
|
||||
if user.Role != "admin" {
|
||||
err = errors.New("no permission")
|
||||
} else {
|
||||
proto.CID_RunningMutex.RLock()
|
||||
for _, v := range proto.CID_Running_Map {
|
||||
resp = append(resp, v...)
|
||||
}
|
||||
proto.CID_RunningMutex.RUnlock()
|
||||
}
|
||||
} else {
|
||||
err = errors.New("request type is error")
|
||||
}
|
||||
return resp, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,29 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/golang-jwt/jwt"
|
||||
"log"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"time"
|
||||
"videoplayer/dao"
|
||||
"videoplayer/proto"
|
||||
"videoplayer/worker"
|
||||
)
|
||||
|
||||
func CreateUser(name, password, email, gender string, age int) uint {
|
||||
return dao.CreateUser(name, password, email, gender, age)
|
||||
id := dao.CreateUser(name, password, email, gender, age)
|
||||
if id != 0 {
|
||||
//添加用户信息到同步列表
|
||||
err := setSyncUserDataSet("add", int(id))
|
||||
if err != nil {
|
||||
return id
|
||||
}
|
||||
}
|
||||
return id
|
||||
}
|
||||
|
||||
func GetUser(name, email, password string) dao.User {
|
||||
|
|
@ -38,6 +54,424 @@ func GetUserByID(id int) []proto.User {
|
|||
return dao.FindUserByID(id)
|
||||
}
|
||||
|
||||
// 获取用户信息,有redis缓存
|
||||
func GetUserByIDWithCache(id int) dao.User {
|
||||
if id <= 0 {
|
||||
return dao.User{}
|
||||
}
|
||||
var user dao.User
|
||||
//先从redis获取
|
||||
key := "user_info_" + strconv.Itoa(id)
|
||||
user_str := worker.GetRedis(key)
|
||||
if user_str != "" {
|
||||
err := json.Unmarshal([]byte(user_str), &user)
|
||||
if err != nil {
|
||||
fmt.Println("get user info , json unmarshal error:", err, "\tuser_str:", user_str)
|
||||
return dao.User{}
|
||||
}
|
||||
} else {
|
||||
user = dao.FindUserByID2(id)
|
||||
if user.ID != 0 {
|
||||
userJson, err := json.Marshal(user)
|
||||
if err != nil {
|
||||
fmt.Println("get user info , json marshal error:", err)
|
||||
return dao.User{}
|
||||
}
|
||||
success := worker.SetRedis(key, string(userJson))
|
||||
if !success {
|
||||
fmt.Println("set redis error,user json:", string(userJson))
|
||||
}
|
||||
}
|
||||
}
|
||||
return user
|
||||
}
|
||||
|
||||
func GetUserByNameLike(name string) []proto.User {
|
||||
return dao.FindUserByNameLike(name)
|
||||
}
|
||||
|
||||
func UpdateUser(user_id int, req proto.UpdateUserInfoReq) (int, error) {
|
||||
cur_user := dao.FindUserByID2(user_id)
|
||||
//fmt.Println("cur_user:", cur_user, "req:", req)
|
||||
if user_id == req.ID && cur_user.Role != "admin" {
|
||||
err := dao.UpdateUserByID3(user_id, req) //用户修改自己的信息,不能修改权限信息
|
||||
//添加修改用户信息到同步列表
|
||||
if err == nil {
|
||||
err2 := setSyncUserDataSet("update", user_id)
|
||||
UpdateUserCache(user_id)
|
||||
if err2 != nil {
|
||||
fmt.Println("set sync user data set error:", err2)
|
||||
return user_id, nil
|
||||
}
|
||||
}
|
||||
return user_id, err
|
||||
} else if cur_user.Role == "admin" {
|
||||
err := dao.UpdateUserByID2(req.ID, req)
|
||||
if err == nil {
|
||||
//添加修改用户信息到同步列表
|
||||
err2 := setSyncUserDataSet("update", req.ID)
|
||||
UpdateUserCache(req.ID)
|
||||
if err2 != nil {
|
||||
fmt.Println("set sync user data set error:", err2)
|
||||
return req.ID, nil
|
||||
}
|
||||
}
|
||||
return req.ID, nil
|
||||
} else {
|
||||
return 0, nil
|
||||
}
|
||||
}
|
||||
|
||||
func UpdateUserCache(id int) {
|
||||
key := "user_info_" + strconv.Itoa(id)
|
||||
if worker.IsContainKey(key) {
|
||||
users := GetUserByID(id)
|
||||
userJson, err := json.Marshal(users[0]) //统一使用User不使用数组
|
||||
if err != nil {
|
||||
fmt.Println("get user info , json marshal error:", err)
|
||||
}
|
||||
success := worker.SetRedis(key, string(userJson))
|
||||
if !success {
|
||||
fmt.Println("set redis error,user json:", string(userJson))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func DeleteUserService(id, user_id int) int {
|
||||
res := 0
|
||||
if user_id == id {
|
||||
res = dao.DeleteUserByID(id)
|
||||
} else {
|
||||
user := dao.FindUserByID2(user_id)
|
||||
if user.Role == "admin" {
|
||||
res = dao.DeleteUserByID(id)
|
||||
}
|
||||
}
|
||||
if res != 0 {
|
||||
//添加删除用户信息到同步列表
|
||||
err := setSyncUserDataSet("delete", id)
|
||||
if err != nil {
|
||||
return res
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
func UserSyncDataFromMaster() {
|
||||
//从接口获取数据
|
||||
url := "https://" + proto.Config.MASTER_SERVER_DOMAIN + "/user/sync"
|
||||
tokens := worker.GetRedisSetMembers("super_permission_tokens")
|
||||
var req proto.SyncUserReq
|
||||
req.Token = tokens[0]
|
||||
req.Device = proto.Config.SERVER_NAME
|
||||
all := worker.GetRedis("user_sync_all")
|
||||
is_all := false //是否全量同步
|
||||
if all == "" || all == "1" {
|
||||
is_all = true
|
||||
//清空数据表
|
||||
err := dao.ClearAllUsers()
|
||||
if err != nil {
|
||||
fmt.Println("All ClearAllUsers error:", err)
|
||||
return
|
||||
}
|
||||
worker.SetRedisForever("user_sync_all", "1")
|
||||
req.Types = 1
|
||||
} else {
|
||||
worker.SetRedisForever("user_sync_all", "2")
|
||||
req.Types = 2
|
||||
}
|
||||
|
||||
user_sync_data, err := worker.SyncDataFromMasterReq2(url, req)
|
||||
if err != nil {
|
||||
fmt.Println("UserSyncDataFromMaster error:", err)
|
||||
return
|
||||
}
|
||||
add_users := user_sync_data.Add
|
||||
update_users := user_sync_data.Update
|
||||
delete_users := user_sync_data.Delete
|
||||
//未成功操作的id
|
||||
var fail_ids []uint
|
||||
|
||||
//添加用户
|
||||
var add_confirm []proto.UserConfirmID
|
||||
for _, v := range add_users {
|
||||
res := dao.AddUserSync(v)
|
||||
if res == 0 {
|
||||
fail_ids = append(fail_ids, v.ID)
|
||||
} else {
|
||||
add_confirm = append(add_confirm, proto.UserConfirmID{ID: v.ID})
|
||||
}
|
||||
}
|
||||
//更新用户
|
||||
var update_confirm []proto.UserConfirmID
|
||||
for _, v := range update_users {
|
||||
res := dao.UpdateUserSync(v)
|
||||
if res == 0 {
|
||||
fail_ids = append(fail_ids, v.ID)
|
||||
} else {
|
||||
update_confirm = append(update_confirm, proto.UserConfirmID{ID: v.ID})
|
||||
}
|
||||
}
|
||||
//删除用户
|
||||
var delete_confirm []proto.UserConfirmID
|
||||
for _, v := range delete_users {
|
||||
res := dao.DeleteUserSync(v)
|
||||
if res == 0 {
|
||||
fail_ids = append(fail_ids, v.ID)
|
||||
} else {
|
||||
delete_confirm = append(delete_confirm, proto.UserConfirmID{ID: v.ID})
|
||||
}
|
||||
}
|
||||
|
||||
//确认同步数据
|
||||
if is_all == false {
|
||||
var data proto.UserSyncConfirm
|
||||
data.Add = add_confirm
|
||||
data.Update = update_confirm
|
||||
data.Delete = delete_confirm
|
||||
//确认同步数据请求
|
||||
var confirm_req proto.SyncUserReq
|
||||
confirm_req.Token = tokens[0]
|
||||
confirm_req.Device = proto.Config.SERVER_NAME
|
||||
confirm_req.Types = 3
|
||||
confirm_req.Confirm = data
|
||||
worker.SyncDataFromMasterReq2(url, confirm_req)
|
||||
} else {
|
||||
worker.SetRedisForever("user_sync_all", "2")
|
||||
}
|
||||
}
|
||||
|
||||
// 同步数据到主服务器-增删改数据
|
||||
func GetUserSyncData(device string) dao.UserSyncResp {
|
||||
key := device + "_sync_user_ids"
|
||||
add_temp_key := device + "_sync_user_ids_add_confirm_temp"
|
||||
update_temp_key := device + "_sync_user_ids_update_confirm_temp"
|
||||
delete_temp_key := device + "_sync_user_ids_delete_confirm_temp"
|
||||
//需要获取暂存集合的并集,清空暂存集合,存入待确认集合
|
||||
add_user_ids := worker.GetRedisSetUnion(key+"_add", add_temp_key)
|
||||
update_user_ids := worker.GetRedisSetUnion(key+"_update", update_temp_key)
|
||||
delete_user_ids := worker.GetRedisSetUnion(key+"_delete", delete_temp_key)
|
||||
add_users := []dao.User{}
|
||||
update_users := []dao.User{}
|
||||
delete_users := []proto.UserDelID{}
|
||||
for _, v := range add_user_ids {
|
||||
id, _ := strconv.Atoi(v)
|
||||
user := dao.FindUserByUserID(id)
|
||||
add_users = append(add_users, user)
|
||||
}
|
||||
|
||||
for _, v := range update_user_ids {
|
||||
id, _ := strconv.Atoi(v)
|
||||
user := dao.FindUserByUserID(id)
|
||||
update_users = append(update_users, user)
|
||||
}
|
||||
|
||||
for _, v := range delete_user_ids {
|
||||
id, _ := strconv.Atoi(v)
|
||||
delete_users = append(delete_users, proto.UserDelID{ID: uint(id)})
|
||||
}
|
||||
//将id存入暂存集合,清空原集合,存入待确认集合主要保证在确认时,有新的数据加入不会在确认时漏掉
|
||||
worker.SetRedisSetUnionAndStore(add_temp_key, key+"_add")
|
||||
worker.ClearRedisSet(key + "_add")
|
||||
worker.SetRedisSetUnionAndStore(update_temp_key, key+"_update")
|
||||
worker.ClearRedisSet(key + "_update")
|
||||
worker.SetRedisSetUnionAndStore(delete_temp_key, key+"_delete")
|
||||
worker.ClearRedisSet(key + "_delete")
|
||||
return dao.UserSyncResp{Add: add_users, Update: update_users, Delete: delete_users}
|
||||
}
|
||||
|
||||
func setSyncUserDataSet(t string, id int) error {
|
||||
devices := worker.GetRedisSetMembers("sync_devices_ids") //主服务器查看从服务器的设备列表
|
||||
fmt.Println("set sync user data set devices:", devices, "t:", t, "id:", id)
|
||||
var err error
|
||||
for _, device := range devices {
|
||||
key := device + "_sync_user_ids"
|
||||
if t == "add" {
|
||||
key_ := key + "_add"
|
||||
worker.SetRedisSetAdd(key_, strconv.Itoa(id))
|
||||
} else if t == "update" {
|
||||
key_ := key + "_update"
|
||||
worker.SetRedisSetAdd(key_, strconv.Itoa(id))
|
||||
} else if t == "delete" {
|
||||
key_ := key + "_delete"
|
||||
worker.SetRedisSetAdd(key_, strconv.Itoa(id))
|
||||
} else {
|
||||
err = errors.New("error")
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// 确认同步数据
|
||||
func ConfirmSyncUserData(device string, data proto.UserSyncConfirm) error {
|
||||
var err error
|
||||
if len(data.Add) > 0 {
|
||||
var ids_add []string
|
||||
|
||||
for _, v := range data.Add {
|
||||
ids_add = append(ids_add, strconv.Itoa(int(v.ID)))
|
||||
}
|
||||
add_key := device + "_sync_user_ids_add_confirm"
|
||||
isSuccess := worker.SetRedisSetAddBatchWithExpire(add_key, ids_add, time.Second*30)
|
||||
if !isSuccess {
|
||||
err = errors.New("set add confirm error")
|
||||
return err
|
||||
}
|
||||
ids_add_confirm_temp := device + "_sync_user_ids_add_confirm_temp"
|
||||
//取差集
|
||||
add_diff := worker.SetRedisSetDiffAndStore(ids_add_confirm_temp, add_key)
|
||||
if add_diff == false {
|
||||
err = errors.New("add diff error")
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if len(data.Update) > 0 {
|
||||
|
||||
var ids_update []string
|
||||
for _, v := range data.Update {
|
||||
ids_update = append(ids_update, strconv.Itoa(int(v.ID)))
|
||||
}
|
||||
update_key := device + "_sync_user_ids_update_confirm"
|
||||
isSuccess := worker.SetRedisSetAddBatchWithExpire(update_key, ids_update, time.Second*30)
|
||||
if !isSuccess {
|
||||
err = errors.New("set update confirm error")
|
||||
return err
|
||||
}
|
||||
ids_update_confirm_temp := device + "_sync_user_ids_update_confirm_temp"
|
||||
|
||||
update_diff := worker.SetRedisSetDiffAndStore(ids_update_confirm_temp, update_key)
|
||||
if update_diff == false {
|
||||
err = errors.New("update diff error")
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if len(data.Delete) > 0 {
|
||||
var ids_delete []string
|
||||
for _, v := range data.Delete {
|
||||
ids_delete = append(ids_delete, strconv.Itoa(int(v.ID)))
|
||||
}
|
||||
del_key := device + "_sync_user_ids_delete_confirm"
|
||||
isSuccess := worker.SetRedisSetAddBatchWithExpire(del_key, ids_delete, time.Second*30)
|
||||
if !isSuccess {
|
||||
err = errors.New("set del confirm error")
|
||||
return err
|
||||
}
|
||||
|
||||
//待确认集合暂存
|
||||
ids_delete_confirm_temp := device + "_sync_user_ids_delete_confirm_temp"
|
||||
delete_diff := worker.SetRedisSetDiffAndStore(ids_delete_confirm_temp, del_key)
|
||||
if delete_diff == false {
|
||||
err = errors.New("delete diff error")
|
||||
return err
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// 生成新的token,存入redis,返回信息
|
||||
func CreateTokenAndSave(user dao.User) (string, error) {
|
||||
var tokenString string
|
||||
var err error
|
||||
key := "user_" + user.Name
|
||||
redis_token := worker.GetRedis(string(key))
|
||||
if redis_token == "" {
|
||||
// 生成 JWT 令牌
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
|
||||
"username": user.Name,
|
||||
"id": user.ID,
|
||||
"exp": time.Now().Add(time.Hour * 10).Unix(), // 令牌过期时间, 10小时后过期
|
||||
})
|
||||
tokenString, err = token.SignedString(proto.SigningKey)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
worker.SetRedisWithExpire("user_"+user.Name, tokenString, time.Hour*10) // 将用户信息存入
|
||||
worker.SetRedisWithExpire(tokenString, tokenString, time.Hour*10) // 设置过期时间为10分钟
|
||||
data := make(map[string]interface{})
|
||||
data["id"] = user.ID
|
||||
data["username"] = user.Name
|
||||
data["email"] = user.Email
|
||||
worker.SetHash(tokenString, data) // 将用户信息存入
|
||||
} else {
|
||||
tokenString = redis_token
|
||||
}
|
||||
// 返回令牌
|
||||
return tokenString, err
|
||||
}
|
||||
|
||||
// 获取用户信息,有redis缓存
|
||||
func GetUserByIDFromUserCenter(id int) dao.User {
|
||||
if id <= 0 {
|
||||
return dao.User{}
|
||||
}
|
||||
var user dao.User
|
||||
//先从redis获取
|
||||
key := "user_info_" + strconv.Itoa(id)
|
||||
userStr := worker.GetRedis(key)
|
||||
//log.Println("user_str:", userStr)
|
||||
if userStr != "" {
|
||||
err := json.Unmarshal([]byte(userStr), &user)
|
||||
if err != nil {
|
||||
fmt.Println("get user info , json unmarshal error:", err, "\tuser_str:", userStr)
|
||||
return dao.User{}
|
||||
}
|
||||
} else {
|
||||
user = GetUserInfoByIDFromUserCenterHttp(id)
|
||||
if user.ID != 0 {
|
||||
userJson, err := json.Marshal(user)
|
||||
if err != nil {
|
||||
fmt.Println("get user info , json marshal error:", err)
|
||||
return dao.User{}
|
||||
}
|
||||
userStr = string(userJson)
|
||||
success := worker.SetRedisWithExpire(key, userStr, time.Second*10)
|
||||
if !success {
|
||||
fmt.Println("set redis error,user json:", userStr)
|
||||
}
|
||||
} else {
|
||||
log.Println("GetUserByIDFromUserCenter user not found, id:", id)
|
||||
log.Println("response user:", user)
|
||||
}
|
||||
}
|
||||
return user
|
||||
}
|
||||
|
||||
type UserInfoResponse struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
Data dao.User `json:"data"`
|
||||
}
|
||||
|
||||
func GetUserInfoByIDFromUserCenterHttp(id int) dao.User {
|
||||
var resp UserInfoResponse
|
||||
url := "https://uc.ljsea.top/user/info?super_id=1"
|
||||
tokens := worker.GetRedisSetMembers("super_permission_tokens")
|
||||
if len(tokens) == 0 {
|
||||
return resp.Data
|
||||
}
|
||||
token := tokens[0]
|
||||
//请求参数
|
||||
req := map[string]int{
|
||||
"id": id,
|
||||
}
|
||||
headers := map[string]string{
|
||||
"token": token,
|
||||
}
|
||||
reqByte, _ := json.Marshal(req)
|
||||
err, respBytes := worker.DoPostRequestJSON(url, reqByte, headers)
|
||||
if err != nil {
|
||||
log.Println("GetUserInfoByIDFromUserCenterHttp error:", err)
|
||||
return resp.Data
|
||||
}
|
||||
if err2 := json.Unmarshal(respBytes, &resp); err2 != nil {
|
||||
log.Println("GetUserInfoByIDFromUserCenterHttp json unmarshal error:", err2)
|
||||
}
|
||||
if resp.Data.ID == 0 {
|
||||
log.Println("GetUserInfoByIDFromUserCenterHttp user not found, resp:", string(respBytes))
|
||||
return resp.Data
|
||||
}
|
||||
return resp.Data
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,14 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"videoplayer/dao"
|
||||
"videoplayer/proto"
|
||||
"videoplayer/worker"
|
||||
)
|
||||
|
||||
func GetVideo(id, auth_id int) dao.Video {
|
||||
|
|
@ -16,29 +19,18 @@ func GetWillDelVideoList(id int) []dao.Video {
|
|||
return dao.FindWillDelVideoList(id)
|
||||
}
|
||||
|
||||
func GetVideoList(auth_id int, start, end, hour string) []dao.Video {
|
||||
func GetVideoList(auth_id, id int, start, end, hour string) []dao.Video {
|
||||
if id > 0 {
|
||||
user := dao.FindUserByID2(auth_id)
|
||||
if user.Role == "admin" {
|
||||
return dao.FindVideoByID2(id) //可根据id查找视频
|
||||
} else {
|
||||
return []dao.Video{dao.FindVideoByID(id, auth_id)}
|
||||
}
|
||||
}
|
||||
if start == "" {
|
||||
return dao.FindVideoListsByAuthID(auth_id)
|
||||
} else {
|
||||
//s, err := time.Parse("2006/1/02 15:04:05", start)
|
||||
//if err != nil {
|
||||
// s, err = time.Parse("2006/01/02 15:04:05", start)
|
||||
//}
|
||||
//e, err2 := time.Parse("2006/1/02 15:04:05", end)
|
||||
//if err2 != nil {
|
||||
// e, err2 = time.Parse("2006/01/02 15:04:05", end)
|
||||
//}
|
||||
//if s.After(e) || err != nil || err2 != nil {
|
||||
// fmt.Println(err)
|
||||
// fmt.Println(err2)
|
||||
// return []dao.Video{}
|
||||
//}
|
||||
start = strings.Replace(start, "/", "-", -1)
|
||||
end = strings.Replace(end, "/", "-", -1)
|
||||
start = strings.Replace(start, " ", " ", -1)
|
||||
end = strings.Replace(end, " ", " ", -1)
|
||||
start = start[0:5] + "0" + start[5:]
|
||||
end = end[0:5] + "0" + end[5:]
|
||||
if hour != "33" {
|
||||
ss := strings.Split(start, " ")
|
||||
ss1 := strings.Split(ss[1], ":")
|
||||
|
|
@ -78,8 +70,16 @@ func GetVideoListByPage(auth_id, page, page_size int) []dao.Video {
|
|||
return dao.GetVideoListByPage(auth_id, page, page_size)
|
||||
}
|
||||
|
||||
func DeleteVideo(id, user int) int {
|
||||
return dao.DeleteVideoByID(id, user)
|
||||
func DeleteVideo(id, user int, tp string) int {
|
||||
if tp == "del_with_logic" {
|
||||
data := map[string]interface{}{"id": id, "auth_id": user, "delete_time": time.Now().Format("2006-01-02 15:04:05"), "method": "delete"}
|
||||
str, _ := json.Marshal(data)
|
||||
SetVideoOption("user-"+strconv.Itoa(user)+"-option", string(str))
|
||||
return dao.LogicDeleteVideoByID(id, user)
|
||||
} else if tp == "del_with_real" {
|
||||
return dao.DeleteVideoByID(id, user)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func QuashVideo(user int, data map[string]interface{}) (int, string) {
|
||||
|
|
@ -92,6 +92,14 @@ func QuashVideo(user int, data map[string]interface{}) (int, string) {
|
|||
}()
|
||||
switch data["method"] {
|
||||
case "delete":
|
||||
video_id := int(data["id"].(float64))
|
||||
res = dao.RollbackVideoByID(video_id, user)
|
||||
if res == 0 {
|
||||
msg = strconv.Itoa(video_id) + " rollback video error"
|
||||
} else {
|
||||
res = 0
|
||||
msg = "success"
|
||||
}
|
||||
case "delay":
|
||||
if data["option"] == "all" {
|
||||
if dao.QuashAllDelay(user, data["delay_day"].(int)) == 0 {
|
||||
|
|
@ -125,29 +133,15 @@ func UpdateVideo(videoPath, videoName string, cameraID, videoID, authID, human,
|
|||
if video.ID == 0 {
|
||||
return false
|
||||
}
|
||||
if videoPath == "" {
|
||||
videoPath = video.VideoPath
|
||||
}
|
||||
if videoName == "" {
|
||||
videoName = video.VideoName
|
||||
}
|
||||
if cameraID == 0 {
|
||||
cameraID = video.CameraID
|
||||
}
|
||||
if human == 0 {
|
||||
human = video.Human
|
||||
}
|
||||
if isDelete == 0 {
|
||||
isDelete = video.IsDelete
|
||||
}
|
||||
if createTime == "" {
|
||||
createTime = video.CreateTime
|
||||
}
|
||||
if endTime == "" {
|
||||
endTime = video.EndTime
|
||||
}
|
||||
if fileSize == 0 {
|
||||
fileSize = video.FileSize
|
||||
}
|
||||
return dao.UpdateVideo(videoPath, videoName, cameraID, videoID, authID, human, isDelete, createTime, endTime, fileSize)
|
||||
}
|
||||
|
||||
func SetVideoOption(key string, value string) {
|
||||
//查看list长度
|
||||
lens := worker.GetRedisListLen(key)
|
||||
if lens > 100 {
|
||||
//移除开头的元素
|
||||
worker.PopRedisList(key)
|
||||
}
|
||||
worker.PushRedisList(key, value)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"db":0,
|
||||
"mysql_dsn":"video_t2:2t2SKHmWEYj2xFKF@tcp(127.0.0.1:3306)/video_t2?charset=utf8mb4&parseTime=True&loc=Local",
|
||||
"pg_dsn":"host=localhost user=video_t2 dbname=video_t2 password=2t2SKHmWEYj2xFKF port=5432 TimeZone=Asia/Shanghai",
|
||||
"redis_addr":"127.0.0.1:6379",
|
||||
"redis_db":2,
|
||||
"redis_user_pw":true,
|
||||
"token_use_redis":true,
|
||||
"redis_password":"lj502138",
|
||||
"token_secret":"mfjurnc_32ndj9dfhj",
|
||||
"cid_base_dir":"/home/lijun/cid/",
|
||||
"file_base_dir":"/home/lijun/file/",
|
||||
"monitor":false,
|
||||
"server_port":"8083"
|
||||
}
|
||||
|
|
@ -0,0 +1,186 @@
|
|||
package worker
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"log"
|
||||
"math"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// MemoryCacheValue 缓存值结构,包含值和过期时间
|
||||
type MemoryCacheValue struct {
|
||||
Value string `json:"value"`
|
||||
ExpireAt int64 `json:"expireAt"` // 过期时间戳,秒级
|
||||
}
|
||||
|
||||
var (
|
||||
memoryCacheData = NewMemoryCache()
|
||||
)
|
||||
|
||||
// MemoryCache 线程安全的内存缓存
|
||||
type MemoryCache struct {
|
||||
data map[string]MemoryCacheValue
|
||||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
// NewMemoryCache 创建新的内存缓存实例
|
||||
func NewMemoryCache() *MemoryCache {
|
||||
return &MemoryCache{
|
||||
data: make(map[string]MemoryCacheValue),
|
||||
}
|
||||
}
|
||||
|
||||
// InitStaticMemoryCache 初始化全局缓存实例
|
||||
func InitStaticMemoryCache() {
|
||||
// 先尝试从文件加载
|
||||
ReadMemoryCacheFromJsonFile()
|
||||
|
||||
}
|
||||
|
||||
// SetWithExp 设置带过期时间的键值对
|
||||
func (mc *MemoryCache) SetWithExp(key string, value string, expireAt int64) {
|
||||
mc.mu.Lock()
|
||||
defer mc.mu.Unlock()
|
||||
mc.data[key] = MemoryCacheValue{value, expireAt}
|
||||
}
|
||||
|
||||
// Get 获取键值,如果已过期则返回空并删除
|
||||
func (mc *MemoryCache) Get(key string) string {
|
||||
// 先加读锁检查
|
||||
mc.mu.RLock()
|
||||
value, ok := mc.data[key]
|
||||
mc.mu.RUnlock()
|
||||
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
|
||||
// 检查是否过期
|
||||
now := time.Now().Unix()
|
||||
if value.ExpireAt > now {
|
||||
return value.Value
|
||||
}
|
||||
|
||||
// 已过期,删除该键
|
||||
mc.mu.Lock()
|
||||
// 二次检查,防止并发情况下已被删除
|
||||
if v, exists := mc.data[key]; exists && v.ExpireAt <= now {
|
||||
delete(mc.data, key)
|
||||
}
|
||||
mc.mu.Unlock()
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
// Set 设置永不过期的键值对
|
||||
func (mc *MemoryCache) Set(key string, value string) {
|
||||
mc.SetWithExp(key, value, math.MaxInt64)
|
||||
}
|
||||
|
||||
// Del 删除指定键
|
||||
func (mc *MemoryCache) Del(key string) {
|
||||
mc.mu.Lock()
|
||||
defer mc.mu.Unlock()
|
||||
delete(mc.data, key)
|
||||
}
|
||||
|
||||
// Clear 清空所有缓存
|
||||
func (mc *MemoryCache) Clear() {
|
||||
mc.mu.Lock()
|
||||
defer mc.mu.Unlock()
|
||||
mc.data = make(map[string]MemoryCacheValue)
|
||||
}
|
||||
|
||||
const CRON_MAX_DEL_NUMBER = 100 // 每次清理的最大数量
|
||||
|
||||
// DeleteMemoryCacheCron 定时清理过期键
|
||||
func DeleteMemoryCacheCron() {
|
||||
memoryCacheData.mu.Lock()
|
||||
defer memoryCacheData.mu.Unlock()
|
||||
|
||||
now := time.Now().Unix()
|
||||
i := 0
|
||||
for key, value := range memoryCacheData.data {
|
||||
if i >= CRON_MAX_DEL_NUMBER {
|
||||
break
|
||||
}
|
||||
if value.ExpireAt < now {
|
||||
delete(memoryCacheData.data, key)
|
||||
i++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GetMemoryCacheFilePath 获取缓存持久化文件路径
|
||||
func GetMemoryCacheFilePath() string {
|
||||
if os.Getenv("OS") == "Windows_NT" {
|
||||
return "C:/Users/Administrator/vp_mc.json"
|
||||
}
|
||||
return "/etc/vp_mc.json"
|
||||
}
|
||||
|
||||
// WriteMemoryCacheToFile 将缓存写入文件持久化
|
||||
func WriteMemoryCacheToFile() {
|
||||
memoryCacheData.mu.RLock()
|
||||
defer memoryCacheData.mu.RUnlock()
|
||||
|
||||
path := GetMemoryCacheFilePath()
|
||||
data, err := json.MarshalIndent(memoryCacheData.data, "", " ")
|
||||
if err != nil {
|
||||
log.Println("mc write file json err:", err)
|
||||
return
|
||||
}
|
||||
|
||||
// 先写入临时文件,再原子替换,防止文件损坏
|
||||
tempPath := path + ".tmp"
|
||||
if err := os.WriteFile(tempPath, data, 0644); err != nil {
|
||||
log.Println("mc write temp file err:", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := os.Rename(tempPath, path); err != nil {
|
||||
log.Println("mc rename file err:", err)
|
||||
os.Remove(tempPath) // 清理临时文件
|
||||
}
|
||||
}
|
||||
|
||||
// ReadMemoryCacheFromJsonFile 从文件加载缓存
|
||||
func ReadMemoryCacheFromJsonFile() {
|
||||
path := GetMemoryCacheFilePath()
|
||||
_, err := os.Stat(path)
|
||||
if err != nil {
|
||||
log.Println("mc file not exists:", err)
|
||||
return
|
||||
}
|
||||
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
log.Println("mc open file err:", err)
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
var data map[string]MemoryCacheValue
|
||||
decoder := json.NewDecoder(file)
|
||||
if err := decoder.Decode(&data); err != nil {
|
||||
log.Println("mc decode file err:", err)
|
||||
return
|
||||
}
|
||||
|
||||
// 过滤已过期的数据
|
||||
now := time.Now().Unix()
|
||||
memoryCacheData.mu.Lock()
|
||||
for k, v := range data {
|
||||
if v.ExpireAt > now || v.ExpireAt == math.MaxInt64 {
|
||||
memoryCacheData.data[k] = v
|
||||
}
|
||||
}
|
||||
memoryCacheData.mu.Unlock()
|
||||
}
|
||||
|
||||
// 提供全局缓存的访问方法
|
||||
func GetGlobalCache() *MemoryCache {
|
||||
return memoryCacheData
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
package worker
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/smtp"
|
||||
)
|
||||
|
||||
type MyEmail struct {
|
||||
SmtpPort int
|
||||
ImapPort int
|
||||
SmtpHost string
|
||||
SmtpUserName string
|
||||
SmtpPassword string
|
||||
}
|
||||
|
||||
func (e *MyEmail) Send(title, content string, toEmail []string) error {
|
||||
//捕获异常
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
fmt.Errorf("MyEmail send mail error: %s", err)
|
||||
}
|
||||
}()
|
||||
|
||||
// 设置邮件头部
|
||||
header := make(map[string]string)
|
||||
header["From"] = e.SmtpUserName
|
||||
header["To"] = toEmail[0]
|
||||
|
||||
header["Subject"] = title
|
||||
|
||||
// 组装邮件消息
|
||||
message := ""
|
||||
for k, v := range header {
|
||||
message += fmt.Sprintf("%s: %s\r\n", k, v)
|
||||
}
|
||||
message += "\r\n" + content
|
||||
// 发送邮件
|
||||
err := smtp.SendMail(e.SmtpHost, smtp.PlainAuth("", e.SmtpUserName, e.SmtpPassword, "pop.qq.com"), e.SmtpUserName, toEmail, []byte(message))
|
||||
if err != nil {
|
||||
//log.Fatalf("smtp error: %s", err)
|
||||
fmt.Errorf("send mail error: %s", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
377
worker/redis.go
377
worker/redis.go
|
|
@ -1,29 +1,36 @@
|
|||
package worker
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/go-redis/redis/v8"
|
||||
"strconv"
|
||||
"time"
|
||||
"videoplayer/proto"
|
||||
)
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"github.com/go-redis/redis/v8"
|
||||
)
|
||||
|
||||
var redisClient *redis.Client // Redis 客户端, 用于连接 Redis 服务器
|
||||
var RedisClient *redis.Client // Redis 客户端, 用于连接 Redis 服务器
|
||||
func InitRedis() error {
|
||||
ctx := context.Background()
|
||||
// 连接redis
|
||||
redisClient = redis.NewClient(&redis.Options{
|
||||
Addr: proto.REDIS_ADDR, // Redis 服务器地址
|
||||
Password: proto.REDIS_PASSWORD, // 如果 Redis 设置了密码
|
||||
DB: proto.REIDS_DB, // 使用的数据库编号
|
||||
})
|
||||
|
||||
if proto.Config.REDIS_User_PW == false {
|
||||
// 连接redis
|
||||
RedisClient = redis.NewClient(&redis.Options{
|
||||
Addr: proto.Config.REDIS_ADDR, // Redis 服务器地址
|
||||
DB: proto.Config.REDIS_DB, // 使用的数据库编号
|
||||
})
|
||||
} else {
|
||||
// 连接redis
|
||||
RedisClient = redis.NewClient(&redis.Options{
|
||||
Addr: proto.Config.REDIS_ADDR, // Redis 服务器地址
|
||||
Password: proto.Config.REDIS_PASSWORD, // 如果 Redis 设置了密码
|
||||
DB: proto.Config.REDIS_DB, // 使用的数据库编号
|
||||
})
|
||||
}
|
||||
|
||||
// 验证 Redis 客户端是否可以正常工作
|
||||
_, err := redisClient.Ping(ctx).Result()
|
||||
_, err := RedisClient.Ping(ctx).Result()
|
||||
if err != nil {
|
||||
fmt.Println("Error connecting to Redis: %v", err)
|
||||
}
|
||||
|
|
@ -32,16 +39,16 @@ func InitRedis() error {
|
|||
|
||||
func CloseRedis() {
|
||||
// 关闭 Redis 客户端
|
||||
if err := redisClient.Close(); err != nil {
|
||||
if err := RedisClient.Close(); err != nil {
|
||||
fmt.Println("Error closing Redis client: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func IsContainKey(key string) bool {
|
||||
ctx := context.Background()
|
||||
val, err := redisClient.Exists(ctx, key).Result() // 检查键是否存在, 如果存在则返回 1, 否则返回 0
|
||||
val, err := RedisClient.Exists(ctx, key).Result() // 检查键是否存在, 如果存在则返回 1, 否则返回 0
|
||||
if err != nil {
|
||||
fmt.Println("Error getting key: %v", err)
|
||||
//fmt.Println("Error getting key: %v", err)
|
||||
return false
|
||||
}
|
||||
if val == 0 {
|
||||
|
|
@ -54,7 +61,18 @@ func IsContainKey(key string) bool {
|
|||
func SetRedis(key string, value string) bool {
|
||||
ctx := context.Background()
|
||||
// 设置键值对, 0 表示不设置过期时间, 如果需要设置过期时间, 可以设置为 time.Second * 10 等
|
||||
err := redisClient.Set(ctx, key, value, time.Minute*30).Err()
|
||||
err := RedisClient.Set(ctx, key, value, time.Minute*30).Err()
|
||||
if err != nil {
|
||||
fmt.Println("Error setting key: %v", err)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// 设置redis,永久
|
||||
func SetRedisForever(key string, value string) bool {
|
||||
ctx := context.Background()
|
||||
err := RedisClient.Set(ctx, key, value, 0).Err()
|
||||
if err != nil {
|
||||
fmt.Println("Error setting key: %v", err)
|
||||
return false
|
||||
|
|
@ -74,12 +92,12 @@ func SetHashWithTime(key string, id int, name, email string, duration time.Durat
|
|||
}
|
||||
|
||||
// 设置哈希表的字段值, 0 表示不设置过期时间, 如果需要设置过期时间, 可以设置为 time.Second * 10 等
|
||||
err := redisClient.HSet(ctx, key, fields).Err()
|
||||
err := RedisClient.HSet(ctx, key, fields).Err()
|
||||
if err != nil {
|
||||
fmt.Println("Error setting key: %v", err)
|
||||
return false
|
||||
}
|
||||
err = redisClient.Expire(ctx, key, time.Hour*10).Err()
|
||||
err = RedisClient.Expire(ctx, key, time.Hour*10).Err()
|
||||
if err != nil {
|
||||
fmt.Println("Error setting key: %v", err)
|
||||
return false
|
||||
|
|
@ -90,12 +108,12 @@ func SetHashWithTime(key string, id int, name, email string, duration time.Durat
|
|||
// 设置redis hash,设置过期时间
|
||||
func SetHash(key string, data map[string]interface{}) bool {
|
||||
ctx := context.Background()
|
||||
err := redisClient.HSet(ctx, key, data).Err()
|
||||
err := RedisClient.HSet(ctx, key, data).Err()
|
||||
if err != nil {
|
||||
fmt.Println("%v :Error setting hash: %v", key, err)
|
||||
return false
|
||||
}
|
||||
err = redisClient.Expire(ctx, key, time.Minute*30).Err()
|
||||
err = RedisClient.Expire(ctx, key, time.Minute*30).Err()
|
||||
if err != nil {
|
||||
fmt.Println("%v :Error setting expire: %v", key, err)
|
||||
return false
|
||||
|
|
@ -105,7 +123,7 @@ func SetHash(key string, data map[string]interface{}) bool {
|
|||
|
||||
func SetHashWithField(key string, field string, value string) bool {
|
||||
ctx := context.Background()
|
||||
err := redisClient.HSet(ctx, key, field, value).Err()
|
||||
err := RedisClient.HSet(ctx, key, field, value).Err()
|
||||
if err != nil {
|
||||
fmt.Println("Error setting key: %v", err)
|
||||
return false
|
||||
|
|
@ -115,7 +133,7 @@ func SetHashWithField(key string, field string, value string) bool {
|
|||
|
||||
func GetHash(key string, field string) string {
|
||||
ctx := context.Background()
|
||||
val, err := redisClient.HGet(ctx, key, field).Result()
|
||||
val, err := RedisClient.HGet(ctx, key, field).Result()
|
||||
if err != nil {
|
||||
fmt.Println("Error getting hash: %v", err)
|
||||
return ""
|
||||
|
|
@ -125,7 +143,7 @@ func GetHash(key string, field string) string {
|
|||
|
||||
func GetHashAll(key string) map[string]string {
|
||||
ctx := context.Background()
|
||||
val, err := redisClient.HGetAll(ctx, key).Result()
|
||||
val, err := RedisClient.HGetAll(ctx, key).Result()
|
||||
if err != nil {
|
||||
fmt.Println("Error getting hash: %v", err)
|
||||
return nil
|
||||
|
|
@ -137,7 +155,7 @@ func GetHashAll(key string) map[string]string {
|
|||
func SetRedisWithExpire(key string, value string, expire time.Duration) bool { // 设置键值对, 0 表示不设置过期时间, 如果需要设置过期时间, 可以设置为 time.Second * 10 等
|
||||
ctx := context.Background()
|
||||
// 设置键值对, 0 表示不设置过期时间, 如果需要设置过期时间, 可以设置为 time.Second * 10 等
|
||||
err := redisClient.Set(ctx, key, value, expire).Err()
|
||||
err := RedisClient.Set(ctx, key, value, expire).Err()
|
||||
if err != nil {
|
||||
fmt.Println("Error setting key: %v", err)
|
||||
return false
|
||||
|
|
@ -148,18 +166,34 @@ func SetRedisWithExpire(key string, value string, expire time.Duration) bool { /
|
|||
// 获取redis
|
||||
func GetRedis(key string) string {
|
||||
ctx := context.Background()
|
||||
val, err := redisClient.Get(ctx, key).Result() // 从 Redis 读取键值, 如果键不存在则返回空字符串, 如果出现错误则返回错误
|
||||
val, err := RedisClient.Get(ctx, key).Result() // 从 Redis 读取键值, 如果键不存在则返回空字符串, 如果出现错误则返回错误
|
||||
if err != nil {
|
||||
fmt.Println(key, " Error getting key: %v", err)
|
||||
//fmt.Println(key, " Error getting key: %v", err)
|
||||
return ""
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
func GetRedisWithExpire(key string) (string, int) {
|
||||
ctx := context.Background()
|
||||
val, err := RedisClient.Get(ctx, key).Result() // 从 Redis 读取键值, 如果键不存在则返回空字符串, 如果出现错误则返回错误
|
||||
if err != nil {
|
||||
//fmt.Println(key, " Error getting key: %v", err)
|
||||
return "", 0
|
||||
} else {
|
||||
// 获取键的过期时间
|
||||
ttl, err2 := RedisClient.TTL(ctx, key).Result()
|
||||
if err2 != nil {
|
||||
return val, -1
|
||||
}
|
||||
return val, int(ttl.Seconds())
|
||||
}
|
||||
}
|
||||
|
||||
// pop redis list from right,as stack
|
||||
func PopRedisList(key string) string {
|
||||
ctx := context.Background()
|
||||
val, err := redisClient.RPop(ctx, key).Result() // 从 Redis 读取键值, 如果键不存在则返回空字符串, 如果出现错误则返回错误
|
||||
val, err := RedisClient.RPop(ctx, key).Result() // 从 Redis 读取键值, 如果键不存在则返回空字符串, 如果出现错误则返回错误
|
||||
if err != nil {
|
||||
fmt.Println(key, " Error reading from Redis: %v", err)
|
||||
return ""
|
||||
|
|
@ -170,7 +204,7 @@ func PopRedisList(key string) string {
|
|||
// pop redis list from left,as queue
|
||||
func PopRedisListLeft(key string) string {
|
||||
ctx := context.Background()
|
||||
val, err := redisClient.LPop(ctx, key).Result() // 从 Redis 读取键值, 如果键不存在则返回空字符串, 如果出现错误则返回错误
|
||||
val, err := RedisClient.LPop(ctx, key).Result() // 从 Redis 读取键值, 如果键不存在则返回空字符串, 如果出现错误则返回错误
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
|
@ -179,7 +213,7 @@ func PopRedisListLeft(key string) string {
|
|||
|
||||
func DelRedis(key string) {
|
||||
ctx := context.Background()
|
||||
err := redisClient.Del(ctx, key).Err()
|
||||
err := RedisClient.Del(ctx, key).Err()
|
||||
if err != nil {
|
||||
fmt.Println("Error deleting key: %v", err)
|
||||
}
|
||||
|
|
@ -188,7 +222,7 @@ func DelRedis(key string) {
|
|||
// push redis list from right
|
||||
func PushRedisList(key string, value string) bool {
|
||||
ctx := context.Background()
|
||||
err := redisClient.RPush(ctx, key, value).Err()
|
||||
err := RedisClient.RPush(ctx, key, value).Err()
|
||||
if err != nil {
|
||||
fmt.Println("Error setting key: %v", err)
|
||||
return false
|
||||
|
|
@ -196,14 +230,24 @@ func PushRedisList(key string, value string) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
func GetRedisListLen(key string) int64 {
|
||||
ctx := context.Background()
|
||||
val, err := RedisClient.LLen(ctx, key).Result()
|
||||
if err != nil {
|
||||
//fmt.Println("Error getting key: %v", err)
|
||||
return 0
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
func PushRedisListWithExpire(key string, value string, expire time.Duration) bool {
|
||||
ctx := context.Background()
|
||||
err := redisClient.RPush(ctx, key, value).Err()
|
||||
err := RedisClient.RPush(ctx, key, value).Err()
|
||||
if err != nil {
|
||||
fmt.Println("Error setting key: %v", err)
|
||||
return false
|
||||
}
|
||||
err = redisClient.Expire(ctx, key, expire).Err()
|
||||
err = RedisClient.Expire(ctx, key, expire).Err()
|
||||
if err != nil {
|
||||
fmt.Println("Error setting key: %v", err)
|
||||
return false
|
||||
|
|
@ -214,7 +258,7 @@ func PushRedisListWithExpire(key string, value string, expire time.Duration) boo
|
|||
// delete redis key
|
||||
func delRedis(key string) {
|
||||
ctx := context.Background()
|
||||
err := redisClient.Del(ctx, key).Err()
|
||||
err := RedisClient.Del(ctx, key).Err()
|
||||
if err != nil {
|
||||
fmt.Println("Error setting key: %v", err)
|
||||
}
|
||||
|
|
@ -240,7 +284,7 @@ func (u *RUser) toJSONString() string {
|
|||
// put hash to redis
|
||||
func hSetRedis(key string, field string, value string) {
|
||||
ctx := context.Background()
|
||||
err := redisClient.HSet(ctx, key, field, value).Err()
|
||||
err := RedisClient.HSet(ctx, key, field, value).Err()
|
||||
if err != nil {
|
||||
fmt.Println("Error setting key: %v", err)
|
||||
}
|
||||
|
|
@ -249,9 +293,268 @@ func hSetRedis(key string, field string, value string) {
|
|||
// get hash from redis
|
||||
func hGetRedis(key string, field string) string {
|
||||
ctx := context.Background()
|
||||
val, err := redisClient.HGet(ctx, key, field).Result()
|
||||
val, err := RedisClient.HGet(ctx, key, field).Result()
|
||||
if err != nil {
|
||||
fmt.Println("Error getting key: %v", err)
|
||||
//fmt.Println("Error getting key: %v", err)
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// 设置set,有过期时间
|
||||
func SetRedisSet(key string, values []string, expire time.Duration) bool {
|
||||
ctx := context.Background()
|
||||
err := RedisClient.SAdd(ctx, key, values).Err()
|
||||
if err != nil {
|
||||
fmt.Println("Error setting key: %v", err)
|
||||
return false
|
||||
}
|
||||
err = RedisClient.Expire(ctx, key, expire).Err()
|
||||
if err != nil {
|
||||
fmt.Println("Error setting key: %v", err)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// 设置set,添加元素
|
||||
func SetRedisSetAdd(key string, value string) bool {
|
||||
ctx := context.Background()
|
||||
err := RedisClient.SAdd(ctx, key, value).Err()
|
||||
if err != nil {
|
||||
fmt.Println("Error setting key: %v", err)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// 批量添加元素
|
||||
func SetRedisSetAddBatchWithExpire(key string, values []string, expire time.Duration) bool {
|
||||
ctx := context.Background()
|
||||
err := RedisClient.SAdd(ctx, key, values).Err()
|
||||
if err != nil {
|
||||
fmt.Println("SetRedisSetAddBatchWithExpire Error setting key: %v", err)
|
||||
return false
|
||||
}
|
||||
err = RedisClient.Expire(ctx, key, expire).Err()
|
||||
if err != nil {
|
||||
fmt.Println("SetRedisSetAddBatchWithExpire Error setting key: %v", err)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
|
||||
}
|
||||
|
||||
// 设置set,添加元素
|
||||
func SetRedisSetAddWithExpire(key string, value string, expire time.Duration) bool {
|
||||
ctx := context.Background()
|
||||
err := RedisClient.SAdd(ctx, key, value).Err()
|
||||
if err != nil {
|
||||
fmt.Println("SetRedisSetAddWithExpire Error setting key: %v", err)
|
||||
return false
|
||||
}
|
||||
err = RedisClient.Expire(ctx, key, expire).Err()
|
||||
if err != nil {
|
||||
fmt.Println("SetRedisSetAddWithExpire Error setting key: %v", err)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// 设置set,删除元素
|
||||
func SetRedisSetRemove(key string, value string) bool {
|
||||
ctx := context.Background()
|
||||
err := RedisClient.SRem(ctx, key, value).Err()
|
||||
if err != nil {
|
||||
fmt.Println("Error setting key: %v", err)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// 获取两个set的交集
|
||||
func GetRedisSetIntersect(key1 string, key2 string) []string {
|
||||
ctx := context.Background()
|
||||
val, err := RedisClient.SInter(ctx, key1, key2).Result()
|
||||
if err != nil {
|
||||
//fmt.Println("Error getting key: %v", err)
|
||||
return nil
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// 查看set是否包含元素
|
||||
func IsContainSet(key string, value string) bool {
|
||||
ctx := context.Background()
|
||||
val, err := RedisClient.SIsMember(ctx, key, value).Result()
|
||||
if err != nil {
|
||||
//fmt.Println("Error getting key: %v", err)
|
||||
return false
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// 查看set的所有元素
|
||||
func GetRedisSetMembers(key string) []string {
|
||||
ctx := context.Background()
|
||||
val, err := RedisClient.SMembers(ctx, key).Result()
|
||||
if err != nil {
|
||||
//fmt.Println("Error getting key: %v", err)
|
||||
return nil
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// BITMAP
|
||||
func SetRedisBitmap(key string, offset int64, value int) bool {
|
||||
ctx := context.Background()
|
||||
err := RedisClient.SetBit(ctx, key, offset, value).Err()
|
||||
if err != nil {
|
||||
//fmt.Println("Error setting key: %v", err)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// BITMAP获取
|
||||
func GetRedisBitmap(key string, offset int64) int {
|
||||
ctx := context.Background()
|
||||
val, err := RedisClient.GetBit(ctx, key, offset).Result()
|
||||
if err != nil {
|
||||
//fmt.Println("Error getting key: %v", err)
|
||||
return 0
|
||||
}
|
||||
return int(val)
|
||||
}
|
||||
|
||||
// 发布订阅者模式-发布消息
|
||||
func Publish(channel string, message string, expire time.Duration) {
|
||||
ctx := context.Background()
|
||||
err := RedisClient.Publish(ctx, channel, message).Err()
|
||||
if err != nil {
|
||||
fmt.Println("Error publishing message: %v", err)
|
||||
}
|
||||
err = RedisClient.Expire(ctx, channel, expire).Err()
|
||||
if err != nil {
|
||||
fmt.Println("Error setting key: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// 发布订阅者模式-订阅消息
|
||||
func Subscribe(channel string) []string {
|
||||
ctx := context.Background()
|
||||
pubsub := RedisClient.Subscribe(ctx, channel)
|
||||
ch := pubsub.Channel()
|
||||
defer pubsub.Close()
|
||||
var messages []string
|
||||
for msg := range ch {
|
||||
messages = append(messages, msg.Payload)
|
||||
}
|
||||
return messages
|
||||
}
|
||||
|
||||
// redis两个set求差集存入第一个set
|
||||
func SetRedisSetDiffAndStore(key1 string, key2 string) bool {
|
||||
ctx := context.Background()
|
||||
err := RedisClient.SDiffStore(ctx, key1, key1, key2).Err() //将key1和key2的差集存入key1
|
||||
if err != nil {
|
||||
fmt.Println("SetRedisSetDiffAndStore Error setting key: %v", err)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// redis将第二个set存入第一个set
|
||||
func SetRedisSetUnionAndStore(key1 string, key2 string) bool {
|
||||
ctx := context.Background()
|
||||
err := RedisClient.SUnionStore(ctx, key1, key1, key2).Err() //将key1和key2的并集存入key1
|
||||
if err != nil {
|
||||
fmt.Println("SetRedisSetUnionAndStore Error setting key: %v", err)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// redis 清空set
|
||||
func ClearRedisSet(key string) bool {
|
||||
ctx := context.Background()
|
||||
err := RedisClient.Del(ctx, key).Err()
|
||||
if err != nil {
|
||||
fmt.Println("Error setting key: %v", err)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// 获取两个集合的并集
|
||||
func GetRedisSetUnion(key1 string, key2 string) []string {
|
||||
ctx := context.Background()
|
||||
val, err := RedisClient.SUnion(ctx, key1, key2).Result()
|
||||
if err != nil {
|
||||
//fmt.Println("Error getting key: %v", err)
|
||||
return nil
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
type RedisInfo struct {
|
||||
Key string
|
||||
Value string
|
||||
Type string
|
||||
Expire int // 过期时间, 单位: 秒
|
||||
}
|
||||
|
||||
// 获取所有的key和value,及其对应的过期时间
|
||||
func GetAllRedisInfo() ([]RedisInfo, error) {
|
||||
ctx := context.Background()
|
||||
keys, err := RedisClient.Keys(ctx, "*").Result()
|
||||
if err != nil {
|
||||
//fmt.Println("Error getting key: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
var redisInfos []RedisInfo
|
||||
for _, key := range keys {
|
||||
//先查看key类型,再根据类型获取value
|
||||
key_type, val, err := getKeyTypeAndData(key)
|
||||
if err != nil {
|
||||
//fmt.Println("Error getting key: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
expire, err := RedisClient.TTL(ctx, key).Result()
|
||||
if err != nil {
|
||||
//fmt.Println("Error getting key: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
redisInfo := RedisInfo{
|
||||
Key: key,
|
||||
Value: val,
|
||||
Type: key_type,
|
||||
Expire: int(expire.Seconds()),
|
||||
}
|
||||
redisInfos = append(redisInfos, redisInfo)
|
||||
}
|
||||
return redisInfos, nil
|
||||
}
|
||||
|
||||
func getKeyTypeAndData(key string) (string, string, error) {
|
||||
ctx := context.Background()
|
||||
key_type := RedisClient.Type(ctx, key).Val()
|
||||
var val interface{}
|
||||
var err error
|
||||
switch key_type {
|
||||
case "string":
|
||||
val, err = RedisClient.Get(ctx, key).Result()
|
||||
case "hash":
|
||||
val, err = RedisClient.HGetAll(ctx, key).Result()
|
||||
case "list":
|
||||
val, err = RedisClient.LRange(ctx, key, 0, -1).Result()
|
||||
case "set":
|
||||
val, err = RedisClient.SMembers(ctx, key).Result()
|
||||
case "zset":
|
||||
val, err = RedisClient.ZRange(ctx, key, 0, -1).Result()
|
||||
case "bitmap":
|
||||
val, err = RedisClient.GetBit(ctx, key, 0).Result()
|
||||
default:
|
||||
val = "unknown type"
|
||||
}
|
||||
return key_type, fmt.Sprintf("%v", val), err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,501 @@
|
|||
package worker
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"videoplayer/dao"
|
||||
"videoplayer/proto"
|
||||
)
|
||||
|
||||
var client *http.Client
|
||||
|
||||
// 初始化
|
||||
func InitReq() {
|
||||
client = &http.Client{}
|
||||
}
|
||||
|
||||
// 发起post请求
|
||||
func Post(url string, bodyType string, body string) (*http.Response, error) {
|
||||
req, err := http.NewRequest("POST", url, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set("Content-Type", bodyType)
|
||||
req.Body = io.NopCloser(strings.NewReader(body))
|
||||
return client.Do(req)
|
||||
}
|
||||
|
||||
// 发送到机器人
|
||||
func SendToRobot(url string, body string) (map[string]interface{}, error) {
|
||||
resp, err := Post(url, "application/json", body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
m := make(map[string]interface{})
|
||||
err = json.NewDecoder(resp.Body).Decode(&m)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// 生成补全的函数
|
||||
func GenerateCompletion(url, prompt string, model string) (map[string]interface{}, error) {
|
||||
data := map[string]interface{}{
|
||||
"model": model,
|
||||
"prompt": prompt,
|
||||
"stream": false,
|
||||
}
|
||||
jsonData, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
client_ := &http.Client{}
|
||||
resp, err := client_.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var result map[string]interface{}
|
||||
err = json.Unmarshal(body, &result)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// 获取同步数据通用方法
|
||||
func SyncDataFromMasterReq(url string, token string) proto.UserSync {
|
||||
//从接口获取数据
|
||||
req, err := http.NewRequest("POST", url, nil)
|
||||
if err != nil {
|
||||
return proto.UserSync{}
|
||||
}
|
||||
req.Header.Set("token", token)
|
||||
//json负载
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
//传输数据
|
||||
m := make(map[string]interface{})
|
||||
m["token"] = token
|
||||
m["device"] = ""
|
||||
|
||||
if client == nil {
|
||||
client = &http.Client{}
|
||||
}
|
||||
client = &http.Client{}
|
||||
//获取数据
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return proto.UserSync{}
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return proto.UserSync{}
|
||||
}
|
||||
var result map[string]interface{}
|
||||
err = json.Unmarshal(body, &result)
|
||||
if err != nil {
|
||||
return proto.UserSync{}
|
||||
}
|
||||
fmt.Println("SyncDataFromMasterReq result:", result)
|
||||
if result["code"].(float64) != 0 {
|
||||
return proto.UserSync{}
|
||||
}
|
||||
var userSync proto.UserSync
|
||||
err = json.Unmarshal([]byte(result["data"].(string)), &userSync)
|
||||
if err != nil {
|
||||
return proto.UserSync{}
|
||||
}
|
||||
return userSync
|
||||
}
|
||||
|
||||
type Response struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
Data proto.UserSync `json:"data"`
|
||||
}
|
||||
|
||||
type ShellResponse struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
Data []dao.Shell `json:"data"`
|
||||
}
|
||||
|
||||
type ShellResponseV2 struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
Data []proto.UpdateShellRespV2 `json:"data"`
|
||||
}
|
||||
|
||||
// 获取数据,全量及增量
|
||||
func SyncDataFromMasterReq2(url string, data proto.SyncUserReq) (proto.UserSync, error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
fmt.Println("SyncDataFromMasterReq2 error:", r)
|
||||
}
|
||||
}()
|
||||
|
||||
var res proto.UserSync
|
||||
//从接口获取数据
|
||||
json_data, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
req, err := http.NewRequest("POST", url, bytes.NewBuffer(json_data))
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
//传输数据
|
||||
if client == nil {
|
||||
client = &http.Client{}
|
||||
}
|
||||
//获取数据
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
//解析数据
|
||||
responseBod, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
var response Response
|
||||
err = json.Unmarshal(responseBod, &response)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
res = response.Data
|
||||
fmt.Println("SyncDataFromMasterReq2 result add data:", len(res.Add), "update data:", len(res.Update), "delete data:", len(res.Delete))
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// 获取待执行的shell
|
||||
func SyncDataFromMasterShellReq2(url string, data proto.SyncUserShellReq) ([]dao.Shell, error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
fmt.Println("SyncDataFromMasterReq2 error:", r)
|
||||
}
|
||||
}()
|
||||
|
||||
var res []dao.Shell
|
||||
//从接口获取数据
|
||||
json_data, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
req, err := http.NewRequest("POST", url, bytes.NewBuffer(json_data))
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("token", data.Token)
|
||||
//传输数据
|
||||
if client == nil {
|
||||
client = &http.Client{}
|
||||
}
|
||||
//获取数据
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
//解析数据
|
||||
responseBod, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
var response ShellResponse
|
||||
err = json.Unmarshal(responseBod, &response)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
res = response.Data
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// 获取待执行的shell
|
||||
func SyncDataFromMasterShellReq3(url string, data proto.SyncUserShellResp) ([]proto.UpdateShellRespV2, error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
fmt.Println("SyncDataFromMasterReq2 error:", r)
|
||||
}
|
||||
}()
|
||||
|
||||
var res []proto.UpdateShellRespV2
|
||||
//从接口获取数据
|
||||
json_data, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
req, err := http.NewRequest("POST", url, bytes.NewBuffer(json_data))
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("token", data.Token)
|
||||
//传输数据
|
||||
if client == nil {
|
||||
client = &http.Client{}
|
||||
}
|
||||
//获取数据
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
//解析数据
|
||||
responseBod, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
var response ShellResponseV2
|
||||
err = json.Unmarshal(responseBod, &response)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
res = response.Data
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func DoPostRequestJSON(url string, jsonData []byte, headers map[string]string) (error, []byte) {
|
||||
httpClient := &http.Client{}
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
fmt.Println("SyncDataFromMasterReq2 error:", r)
|
||||
}
|
||||
}()
|
||||
|
||||
//从接口获取数据
|
||||
req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
|
||||
if err != nil {
|
||||
return err, nil
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36 Edg/136.0.0.0")
|
||||
//设置header
|
||||
for k, v := range headers {
|
||||
req.Header.Set(k, v)
|
||||
}
|
||||
//传输数据
|
||||
if httpClient == nil {
|
||||
httpClient = &http.Client{}
|
||||
}
|
||||
//获取数据
|
||||
resp, err := httpClient.Do(req)
|
||||
if err != nil {
|
||||
return err, nil
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
//解析数据
|
||||
responseBod, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return err, nil
|
||||
}
|
||||
return err, responseBod
|
||||
}
|
||||
|
||||
func DoPostRequestForm(url string, jsonData []byte, headers map[string]string) (error, []byte) {
|
||||
httpClient := &http.Client{}
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
fmt.Println("SyncDataFromMasterReq2 error:", r)
|
||||
}
|
||||
}()
|
||||
|
||||
// 创建一个新的 buffer 用于存储 multipart/form-data 请求体
|
||||
body := &bytes.Buffer{}
|
||||
writer := multipart.NewWriter(body)
|
||||
// 修改 data 类型为 map[string]interface{} 以支持不同类型的值
|
||||
var data map[string]interface{}
|
||||
err2 := json.Unmarshal(jsonData, &data)
|
||||
if err2 != nil {
|
||||
log.Println("do post json unmarshal error:", err2)
|
||||
return err2, nil
|
||||
}
|
||||
|
||||
var err error
|
||||
for k, v := range data {
|
||||
switch val := v.(type) {
|
||||
case bool:
|
||||
// 处理布尔类型的值
|
||||
err = writer.WriteField(k, strconv.FormatBool(val))
|
||||
case string:
|
||||
// 处理字符串类型的值
|
||||
err = writer.WriteField(k, val)
|
||||
default:
|
||||
// 其他类型可以根据需要扩展处理逻辑
|
||||
log.Printf("Unsupported type for field %s: %T\n", k, v)
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
log.Println("write field error:", err)
|
||||
return err, nil
|
||||
}
|
||||
}
|
||||
|
||||
// 关闭 writer 以完成请求体的构建
|
||||
err = writer.Close()
|
||||
if err != nil {
|
||||
return err, nil
|
||||
}
|
||||
|
||||
// 创建 POST 请求
|
||||
req, err := http.NewRequest("POST", url, body)
|
||||
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36 Edg/136.0.0.0")
|
||||
if err != nil {
|
||||
return err, nil
|
||||
}
|
||||
|
||||
// 设置 Content-Type 为 multipart/form-data,并带上 boundary
|
||||
req.Header.Set("Content-Type", writer.FormDataContentType())
|
||||
|
||||
// 设置其他自定义请求头
|
||||
for k, v := range headers {
|
||||
req.Header.Set(k, v)
|
||||
}
|
||||
|
||||
// 发送请求
|
||||
resp, err := httpClient.Do(req)
|
||||
if err != nil {
|
||||
return err, nil
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// 读取响应体
|
||||
responseBod, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return err, nil
|
||||
}
|
||||
|
||||
return nil, responseBod
|
||||
}
|
||||
|
||||
func DoPostRequestFormUrlEncoded(url_ string, jsonData []byte, headers map[string]string) (error, []byte) {
|
||||
httpClient := &http.Client{}
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
log.Println("SyncDataFromMasterReq2 error:", r)
|
||||
}
|
||||
}()
|
||||
|
||||
// 解析 JSON 数据
|
||||
var data map[string]interface{}
|
||||
err := json.Unmarshal(jsonData, &data)
|
||||
if err != nil {
|
||||
log.Println("do post json unmarshal error:", err)
|
||||
return err, nil
|
||||
}
|
||||
|
||||
// 创建 url.Values 来存储请求参数
|
||||
reqData := url.Values{}
|
||||
for k, v := range data {
|
||||
switch val := v.(type) {
|
||||
case bool:
|
||||
// 处理布尔类型的值
|
||||
reqData.Set(k, strconv.FormatBool(val))
|
||||
case string:
|
||||
// 处理字符串类型的值
|
||||
reqData.Set(k, val)
|
||||
default:
|
||||
// 其他类型可以根据需要扩展处理逻辑
|
||||
log.Printf("Unsupported type for field %s: %T\n", k, v)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// 将 url.Values 编码为 URL 编码的格式
|
||||
encodedData := reqData.Encode()
|
||||
|
||||
// 创建 POST 请求
|
||||
req, err := http.NewRequest("POST", url_, bytes.NewBufferString(encodedData))
|
||||
if err != nil {
|
||||
return err, nil
|
||||
}
|
||||
|
||||
// 设置请求头
|
||||
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36 Edg/136.0.0.0")
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
|
||||
// 设置其他自定义请求头
|
||||
for k, v := range headers {
|
||||
req.Header.Set(k, v)
|
||||
}
|
||||
|
||||
// 发送请求
|
||||
resp, err := httpClient.Do(req)
|
||||
if err != nil {
|
||||
return err, nil
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// 读取响应体
|
||||
responseBod, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return err, nil
|
||||
}
|
||||
|
||||
return nil, responseBod
|
||||
}
|
||||
|
||||
func DoGetRequest(url string, headers map[string]string) (error, []byte) {
|
||||
httpClient := &http.Client{}
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
fmt.Println("SyncDataFromMasterReq2 error:", r)
|
||||
}
|
||||
}()
|
||||
|
||||
//从接口获取数据
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36 Edg/136.0.0.0")
|
||||
if err != nil {
|
||||
return err, nil
|
||||
}
|
||||
//设置header
|
||||
for k, v := range headers {
|
||||
req.Header.Set(k, v)
|
||||
}
|
||||
//传输数据
|
||||
if httpClient == nil {
|
||||
httpClient = &http.Client{}
|
||||
}
|
||||
//获取数据
|
||||
resp, err := httpClient.Do(req)
|
||||
if err != nil {
|
||||
return err, nil
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
//解析数据
|
||||
responseBod, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return err, nil
|
||||
}
|
||||
return err, responseBod
|
||||
}
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
package worker
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/md5"
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
mrand "math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
func GetRandomString(l int) string {
|
||||
str := "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
bytes := []byte(str)
|
||||
var result []byte
|
||||
for i := 0; i < l; i++ {
|
||||
result = append(result, bytes[mrand.Intn(len(bytes))])
|
||||
}
|
||||
return string(result)
|
||||
}
|
||||
|
||||
func GetCurrentTimestamp() int64 {
|
||||
// 获取当前时间戳
|
||||
return time.Now().Unix()
|
||||
}
|
||||
|
||||
// AESEncrypt 函数使用AES-GCM算法对明文进行加密
|
||||
func AESEncrypt(plaintext []byte, key []byte) (string, error) {
|
||||
// 创建AES加密块
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// 创建GCM模式的加密器
|
||||
gcm, err := cipher.NewGCM(block)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// 生成随机的nonce
|
||||
nonce := make([]byte, gcm.NonceSize())
|
||||
if _, err = io.ReadFull(rand.Reader, nonce); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// 执行加密操作
|
||||
ciphertext := gcm.Seal(nonce, nonce, plaintext, nil)
|
||||
|
||||
// 将加密结果转换为Base64编码字符串
|
||||
return base64.StdEncoding.EncodeToString(ciphertext), nil
|
||||
}
|
||||
|
||||
// AESDecrypt 函数使用AES-GCM算法对密文进行解密
|
||||
func AESDecrypt(ciphertext string, key []byte) ([]byte, error) {
|
||||
// 将Base64编码的密文转换为字节切片
|
||||
data, err := base64.StdEncoding.DecodeString(ciphertext)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 创建AES加密块
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 创建GCM模式的解密器
|
||||
gcm, err := cipher.NewGCM(block)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 提取nonce和真正的密文
|
||||
nonceSize := gcm.NonceSize()
|
||||
if len(data) < nonceSize {
|
||||
return nil, fmt.Errorf("密文长度过短")
|
||||
}
|
||||
nonce, ciphertextBytes := data[:nonceSize], data[nonceSize:]
|
||||
|
||||
// 执行解密操作
|
||||
return gcm.Open(nil, nonce, ciphertextBytes, nil)
|
||||
}
|
||||
|
||||
func GenerateMD5(secretKey string) string {
|
||||
hasher := md5.New()
|
||||
hasher.Write([]byte(secretKey))
|
||||
return hex.EncodeToString(hasher.Sum(nil)) // 将二进制数据转换为十六进制字符串
|
||||
}
|
||||
Loading…
Reference in New Issue