├── .github
└── workflows
│ ├── go.yml
│ └── release.yaml
├── .gitignore
├── .goreleaser.yaml
├── .vscode
└── launch.json
├── DBPacth
└── v1.0.1-v1.0.2.sql
├── LICENSE
├── README.md
├── code-push.sql
├── config
├── app.json
├── app.prod.json
└── config.go
├── db
├── db.go
└── redis
│ └── redis.go
├── go.mod
├── go.sum
├── main.go
├── middleware
└── middleware.go
├── model
├── app.go
├── base.go
├── constants
│ ├── constants.go
│ └── token_info.go
├── deployment.go
├── deploymentVersion.go
├── package.go
├── token.go
└── user.go
├── request
├── app.go
├── client.go
└── user.go
└── utils
└── utils.go
/.github/workflows/go.yml:
--------------------------------------------------------------------------------
1 | # This workflow will build a golang project
2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go
3 |
4 | name: Go
5 |
6 | on:
7 | push:
8 | branches: [ "main" ]
9 | pull_request:
10 | branches: [ "main" ]
11 | pull_request_review:
12 | types: [submitted, dismissed]
13 |
14 | jobs:
15 |
16 | build:
17 | runs-on: ubuntu-latest
18 | steps:
19 | - uses: actions/checkout@v4
20 |
21 | - name: Set up Go
22 | uses: actions/setup-go@v4
23 | with:
24 | go-version: '1.21.5'
25 | - name: Install dependencies
26 | run: go get .
27 | - name: Build
28 | run: go build -v ./...
29 | - name: Test with the Go CLI
30 | run: go test
31 |
--------------------------------------------------------------------------------
/.github/workflows/release.yaml:
--------------------------------------------------------------------------------
1 | name: goreleaser
2 |
3 | on:
4 | push:
5 | # run only against tags
6 | tags:
7 | - '*'
8 |
9 | permissions:
10 | contents: write
11 | # packages: write
12 | # issues: write
13 |
14 | jobs:
15 | goreleaser:
16 | runs-on: ubuntu-latest
17 | steps:
18 | - uses: actions/checkout@v3
19 | with:
20 | fetch-depth: 0
21 | - run: git fetch --force --tags
22 | - uses: actions/setup-go@v3
23 | with:
24 | go-version: '1.21.5'
25 | cache: true
26 | # More assembly might be required: Docker logins, GPG, etc. It all depends
27 | # on your needs.
28 | - uses: goreleaser/goreleaser-action@v4
29 | with:
30 | # either 'goreleaser' (default) or 'goreleaser-pro':
31 | distribution: goreleaser
32 | version: latest
33 | args: release --clean
34 | env:
35 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
36 | # Your GoReleaser Pro key, if you are using the 'goreleaser-pro'
37 | # distribution:
38 | # GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }}
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | config/app.dev.json
2 | bundels/*
3 | __debug_bin*
--------------------------------------------------------------------------------
/.goreleaser.yaml:
--------------------------------------------------------------------------------
1 | # This is an example .goreleaser.yml file with some sensible defaults.
2 | # Make sure to check the documentation at https://goreleaser.com
3 | before:
4 | hooks:
5 | # You may remove this if you don't use go modules.
6 | - go mod tidy
7 | # you may remove this if you don't need go generate
8 | - go generate ./...
9 | builds:
10 | - env:
11 | - CGO_ENABLED=0
12 | goos:
13 | - linux
14 | - windows
15 | - darwin
16 |
17 | archives:
18 | - format: tar.gz
19 | # this name template makes the OS and Arch compatible with the results of uname.
20 | name_template: >-
21 | {{ .ProjectName }}_
22 | {{- title .Os }}_
23 | {{- if eq .Arch "amd64" }}x86_64
24 | {{- else if eq .Arch "386" }}i386
25 | {{- else }}{{ .Arch }}{{ end }}
26 | {{- if .Arm }}v{{ .Arm }}{{ end }}
27 | # use zip for windows archives
28 | format_overrides:
29 | - goos: windows
30 | format: zip
31 | checksum:
32 | name_template: 'checksums.txt'
33 | snapshot:
34 | name_template: "{{ incpatch .Version }}-next"
35 | changelog:
36 | sort: asc
37 | filters:
38 | exclude:
39 | - '^docs:'
40 | - '^test:'
41 |
42 | # The lines beneath this are called `modelines`. See `:help modeline`
43 | # Feel free to remove those if you don't want/use them.
44 | # yaml-language-server: $schema=https://goreleaser.com/static/schema.json
45 | # vim: set ts=2 sw=2 tw=0 fo=cnqoj
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "name": "Launch Package",
9 | "type": "go",
10 | "request": "launch",
11 | "mode": "auto",
12 | "program": "${workspaceFolder}/main.go"
13 | }
14 | ]
15 | }
--------------------------------------------------------------------------------
/DBPacth/v1.0.1-v1.0.2.sql:
--------------------------------------------------------------------------------
1 | ALTER TABLE `package`
2 | ADD COLUMN `deployment_version_id` INT NULL AFTER `deployment_id`;
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 htdcx
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # code-push-server-go
2 | Codepush server go is compatible with [react-native-code-push](https://github.com/microsoft/react-native-code-push). Need to be used with [code-push-go](https://github.com/htdcx/code-push-go). Only supported react-native
3 |
4 | ## Support version
5 | - [mysql](https://dev.mysql.com/downloads/mysql/) >= 8.0
6 | - [golang](https://go.dev/dl/) >= 1.21.5
7 | - [redis](https://redis.io/downloads/) >= 5.0
8 |
9 | ## Support client version
10 | - [react-native-code-push](https://github.com/microsoft/react-native-code-push) >= 7.0
11 |
12 | ## Support storage
13 | - Local
14 | - AWS S3
15 | - FTP
16 |
17 | ## Before installation, please ensure that the following procedures have been installed
18 | - mysql
19 | - golang
20 | - redis
21 |
22 | ## Install code-push-server
23 | ```shell
24 | git clone https://github.com/htdcx/code-push-server-go.git
25 | cd code-push-server-go
26 | import code-push.sql to mysql
27 | ```
28 | ### Configuration mysql,redis,storage
29 | ``` shell
30 | cd config
31 | vi (app.json or app.dev.json or app.prod.json)
32 | # app.json
33 | {
34 | "mode":"prod" #run read config app.{mode}.json
35 | }
36 | # app.prod.json
37 | {
38 | "DBUser": {
39 | "Write": {
40 | "UserName": "",
41 | "Password": "",
42 | "Host": "127.0.0.1",
43 | "Port": 3306,
44 | "DBname": ""
45 | },
46 | "MaxIdleConns": 10,
47 | "MaxOpenConns": 100,
48 | "ConnMaxLifetime": 1
49 | },
50 | "Redis": {
51 | "Host": "127.0.0.1",
52 | "Port": 6379,
53 | "DBIndex": 0,
54 | "UserName": "",
55 | "Password": ""
56 | },
57 | "CodePush": {
58 | "FileLocal":(local,aws,ftp),
59 | "Local":{
60 | "SavePath":"./bundles"
61 | },
62 | "Aws":{
63 | "Endpoint":"",
64 | "Region":"",
65 | "S3ForcePathStyle":true,
66 | "KeyId":"",
67 | "Secret":"",
68 | "Bucket":""
69 | },
70 | "Ftp":{
71 | "ServerUrl":"",
72 | "UserName":"",
73 | "Password":""
74 | }
75 | },
76 | "UrlPrefix": "/",
77 | "ResourceUrl": (nginx config url or s3),
78 | "Port": ":8080",
79 | "TokenExpireTime": 30 (day)
80 | }
81 |
82 | ```
83 | #### Build
84 | ``` shell
85 | #MacOS pack GOOS:windows,darwin
86 | CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o code-push-server-go(.exe) main.go
87 |
88 | #Windows pack
89 | set GOARCH=amd64
90 | set GOOS=linux #windows,darwin
91 | go build -o code-push-server-go(.exe) main.go
92 |
93 | #copy config/app.(model).json and config/app.json to run dir
94 |
95 | #Linux server
96 | chmod +x code-push-server-go
97 |
98 | #run
99 | ./code-push-server-go
100 | ```
101 | ### Default user name and password
102 | - Username:admin
103 | - Password:admin
104 |
105 | ### Change password and user name
106 | ``` shell
107 | Version >= 1.0.5 :./code-push-go change_password
108 | Version <= 1.0.4 :Change mysql users tables (password need md5)
109 | ```
110 |
111 | ### Use [code-push-go](https://github.com/htdcx/code-push-go)
112 | ``` shell
113 | ./code-push-go login -u (userName) -p (password) -h (serverUrl)
114 | ```
115 | ### Configuration client [react-native-code-push](https://github.com/microsoft/react-native-code-push)
116 |
117 | ``` shell
118 | #ios add to Info.plist
119 | CodePushServerURL
120 | ${CODE_PUSH_SERVER_URL}
121 |
122 | #android add to res/value/strings.xml
123 | ${CODE_PUSH_SERVER_URL}
124 | ```
125 |
126 | ## License
127 | MIT License [Read](https://github.com/htdcx/code-push-server-go/blob/main/LICENSE)
128 |
--------------------------------------------------------------------------------
/code-push.sql:
--------------------------------------------------------------------------------
1 | CREATE DATABASE IF NOT EXISTS `code-push` /*!40100 DEFAULT CHARACTER SET utf8 */ /*!80016 DEFAULT ENCRYPTION='N' */;
2 | USE `code-push`;
3 | -- MySQL dump 10.13 Distrib 8.0.34, for macos13 (arm64)
4 | --
5 | -- Host: localhost Database: code-push
6 | -- ------------------------------------------------------
7 | -- Server version 8.0.27
8 |
9 | /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
10 | /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
11 | /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
12 | /*!50503 SET NAMES utf8 */;
13 | /*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
14 | /*!40103 SET TIME_ZONE='+00:00' */;
15 | /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
16 | /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
17 | /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
18 | /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
19 |
20 | --
21 | -- Table structure for table `apps`
22 | --
23 |
24 | DROP TABLE IF EXISTS `apps`;
25 | /*!40101 SET @saved_cs_client = @@character_set_client */;
26 | /*!50503 SET character_set_client = utf8mb4 */;
27 | CREATE TABLE `apps` (
28 | `id` int NOT NULL AUTO_INCREMENT,
29 | `uid` int DEFAULT NULL,
30 | `app_name` varchar(256) DEFAULT NULL,
31 | `os` int DEFAULT NULL,
32 | `create_time` bigint DEFAULT NULL,
33 | PRIMARY KEY (`id`)
34 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
35 | /*!40101 SET character_set_client = @saved_cs_client */;
36 |
37 | --
38 | -- Dumping data for table `apps`
39 | --
40 |
41 | LOCK TABLES `apps` WRITE;
42 | /*!40000 ALTER TABLE `apps` DISABLE KEYS */;
43 | /*!40000 ALTER TABLE `apps` ENABLE KEYS */;
44 | UNLOCK TABLES;
45 |
46 | --
47 | -- Table structure for table `deployment`
48 | --
49 |
50 | DROP TABLE IF EXISTS `deployment`;
51 | /*!40101 SET @saved_cs_client = @@character_set_client */;
52 | /*!50503 SET character_set_client = utf8mb4 */;
53 | CREATE TABLE `deployment` (
54 | `id` int NOT NULL AUTO_INCREMENT,
55 | `app_id` int DEFAULT NULL,
56 | `name` varchar(256) DEFAULT NULL,
57 | `key` varchar(256) DEFAULT NULL,
58 | `version_id` int DEFAULT NULL,
59 | `update_time` bigint DEFAULT NULL,
60 | `create_time` bigint DEFAULT NULL,
61 | PRIMARY KEY (`id`)
62 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
63 | /*!40101 SET character_set_client = @saved_cs_client */;
64 |
65 | --
66 | -- Dumping data for table `deployment`
67 | --
68 |
69 | LOCK TABLES `deployment` WRITE;
70 | /*!40000 ALTER TABLE `deployment` DISABLE KEYS */;
71 | /*!40000 ALTER TABLE `deployment` ENABLE KEYS */;
72 | UNLOCK TABLES;
73 |
74 | --
75 | -- Table structure for table `deployment_version`
76 | --
77 |
78 | DROP TABLE IF EXISTS `deployment_version`;
79 | /*!40101 SET @saved_cs_client = @@character_set_client */;
80 | /*!50503 SET character_set_client = utf8mb4 */;
81 | CREATE TABLE `deployment_version` (
82 | `id` int NOT NULL AUTO_INCREMENT,
83 | `deployment_id` int DEFAULT NULL,
84 | `app_version` varchar(45) DEFAULT NULL,
85 | `version_num` bigint DEFAULT NULL,
86 | `current_package` int DEFAULT NULL,
87 | `update_time` bigint DEFAULT NULL,
88 | `create_time` bigint DEFAULT NULL,
89 | PRIMARY KEY (`id`)
90 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
91 | /*!40101 SET character_set_client = @saved_cs_client */;
92 |
93 | --
94 | -- Dumping data for table `deployment_version`
95 | --
96 |
97 | LOCK TABLES `deployment_version` WRITE;
98 | /*!40000 ALTER TABLE `deployment_version` DISABLE KEYS */;
99 | /*!40000 ALTER TABLE `deployment_version` ENABLE KEYS */;
100 | UNLOCK TABLES;
101 |
102 | --
103 | -- Table structure for table `package`
104 | --
105 |
106 | DROP TABLE IF EXISTS `package`;
107 | /*!40101 SET @saved_cs_client = @@character_set_client */;
108 | /*!50503 SET character_set_client = utf8mb4 */;
109 | CREATE TABLE `package` (
110 | `id` int NOT NULL AUTO_INCREMENT,
111 | `deployment_id` int DEFAULT NULL,
112 | `deployment_version_id` int DEFAULT NULL,
113 | `size` bigint DEFAULT NULL,
114 | `hash` varchar(256) DEFAULT NULL,
115 | `description` TEXT DEFAULT NULL,
116 | `download` varchar(256) DEFAULT NULL,
117 | `active` int DEFAULT '0',
118 | `failed` int DEFAULT '0',
119 | `installed` int DEFAULT '0',
120 | `create_time` bigint DEFAULT NULL,
121 | PRIMARY KEY (`id`)
122 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
123 | /*!40101 SET character_set_client = @saved_cs_client */;
124 |
125 | -- `description` is not part of v1.0.1, it can be added by
126 | -- ALTER TABLE `package` ADD `description` TEXT DEFAULT NULL;
127 |
128 | --
129 | -- Dumping data for table `package`
130 | --
131 |
132 | LOCK TABLES `package` WRITE;
133 | /*!40000 ALTER TABLE `package` DISABLE KEYS */;
134 | /*!40000 ALTER TABLE `package` ENABLE KEYS */;
135 | UNLOCK TABLES;
136 |
137 | --
138 | -- Table structure for table `token`
139 | --
140 |
141 | DROP TABLE IF EXISTS `token`;
142 | /*!40101 SET @saved_cs_client = @@character_set_client */;
143 | /*!50503 SET character_set_client = utf8mb4 */;
144 | CREATE TABLE `token` (
145 | `id` int NOT NULL AUTO_INCREMENT,
146 | `uid` int DEFAULT NULL,
147 | `token` varchar(256) DEFAULT NULL,
148 | `expire_time` bigint DEFAULT NULL,
149 | `del` int DEFAULT NULL,
150 | PRIMARY KEY (`id`)
151 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
152 | /*!40101 SET character_set_client = @saved_cs_client */;
153 |
154 | --
155 | -- Dumping data for table `token`
156 | --
157 |
158 | LOCK TABLES `token` WRITE;
159 | /*!40000 ALTER TABLE `token` DISABLE KEYS */;
160 | /*!40000 ALTER TABLE `token` ENABLE KEYS */;
161 | UNLOCK TABLES;
162 |
163 | --
164 | -- Table structure for table `users`
165 | --
166 |
167 | DROP TABLE IF EXISTS `users`;
168 | /*!40101 SET @saved_cs_client = @@character_set_client */;
169 | /*!50503 SET character_set_client = utf8mb4 */;
170 | CREATE TABLE `users` (
171 | `id` int NOT NULL,
172 | `user_name` varchar(45) DEFAULT NULL,
173 | `password` varchar(45) DEFAULT NULL,
174 | PRIMARY KEY (`id`)
175 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
176 | /*!40101 SET character_set_client = @saved_cs_client */;
177 |
178 | --
179 | -- Dumping data for table `users`
180 | --
181 |
182 | LOCK TABLES `users` WRITE;
183 | /*!40000 ALTER TABLE `users` DISABLE KEYS */;
184 | INSERT INTO `users` VALUES (1,'admin','21232f297a57a5a743894a0e4a801fc3');
185 | /*!40000 ALTER TABLE `users` ENABLE KEYS */;
186 | UNLOCK TABLES;
187 | /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
188 |
189 | /*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
190 | /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
191 | /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
192 | /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
193 | /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
194 | /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
195 | /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
196 |
197 | -- Dump completed on 2024-04-22 17:35:58
198 |
--------------------------------------------------------------------------------
/config/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "mode":"prod"
3 | }
--------------------------------------------------------------------------------
/config/app.prod.json:
--------------------------------------------------------------------------------
1 | {
2 | "DBUser": {
3 | "Write": {
4 | "UserName": "root",
5 | "Password": "",
6 | "Host": "127.0.0.1",
7 | "Port": 3306,
8 | "DBname": "code-push"
9 | },
10 | "MaxIdleConns": 10,
11 | "MaxOpenConns": 100,
12 | "ConnMaxLifetime": 1
13 | },
14 | "Redis": {
15 | "Host": "127.0.0.1",
16 | "Port": 6379,
17 | "DBIndex": 0,
18 | "UserName": "",
19 | "Password": ""
20 | },
21 | "CodePush": {
22 | "FileLocal":"local",
23 | "Local":{
24 | "SavePath":"./bundles"
25 | },
26 | "Aws":{
27 | "Endpoint":"",
28 | "Region":"",
29 | "S3ForcePathStyle":true,
30 | "KeyId":"",
31 | "Secret":"",
32 | "Bucket":""
33 | },
34 | "Ftp":{
35 | "ServerUrl":"",
36 | "UserName":"",
37 | "Password":""
38 | }
39 | },
40 | "UrlPrefix": "/",
41 | "ResourceUrl": "",
42 | "Port": ":8080",
43 | "TokenExpireTime": 30
44 | }
--------------------------------------------------------------------------------
/config/config.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | import (
4 | "encoding/json"
5 | "os"
6 | "os/exec"
7 | "path/filepath"
8 | "strings"
9 | )
10 |
11 | var configFile *appConfig
12 |
13 | func getExcPath() string {
14 | file, _ := exec.LookPath(os.Args[0])
15 | // 获取包含可执行文件名称的路径
16 | path, _ := filepath.Abs(file)
17 | // 获取可执行文件所在目录
18 | index := strings.LastIndex(path, string(os.PathSeparator))
19 | ret := path[:index]
20 | return strings.Replace(ret, "\\", "/", -1)
21 | }
22 |
23 | func GetConfig() appConfig {
24 | if configFile != nil {
25 | return *configFile
26 | }
27 | path := getExcPath()
28 | var mode modeConfig = readJson[modeConfig](path + "/config/app.json")
29 |
30 | appConfig := readJson[appConfig](path + "/config/app." + mode.Mode + ".json")
31 | configFile = &appConfig
32 | return *configFile
33 | }
34 |
35 | func readJson[T any](path string) T {
36 | file, err := os.Open(path)
37 | if err != nil {
38 | panic(path + " config not found")
39 | }
40 | defer file.Close()
41 | decoder := json.NewDecoder(file)
42 |
43 | var jsonF T
44 | decoder.Decode(&jsonF)
45 | return jsonF
46 | }
47 |
48 | type modeConfig struct {
49 | Mode string
50 | }
51 |
52 | type appConfig struct {
53 | DBUser dbConfig
54 | Redis redisConfig
55 | CodePush codePush
56 | UrlPrefix string
57 | Port string
58 | ResourceUrl string
59 | TokenExpireTime int64
60 | }
61 | type dbConfig struct {
62 | Write dbConfigObj
63 | MaxIdleConns uint
64 | MaxOpenConns uint
65 | ConnMaxLifetime uint
66 | }
67 | type dbConfigObj struct {
68 | UserName string
69 | Password string
70 | Host string
71 | Port uint
72 | DBname string
73 | }
74 | type redisConfig struct {
75 | Host string
76 | Port uint
77 | DBIndex uint
78 | UserName string
79 | Password string
80 | }
81 | type codePush struct {
82 | FileLocal string
83 | Local localConfig
84 | Aws awsConfig
85 | Ftp ftpConfig
86 | }
87 | type awsConfig struct {
88 | Endpoint string
89 | Region string
90 | S3ForcePathStyle bool
91 | KeyId string
92 | Secret string
93 | Bucket string
94 | }
95 | type ftpConfig struct {
96 | ServerUrl string
97 | UserName string
98 | Password string
99 | }
100 | type localConfig struct {
101 | SavePath string
102 | }
103 |
--------------------------------------------------------------------------------
/db/db.go:
--------------------------------------------------------------------------------
1 | package db
2 |
3 | import (
4 | "strconv"
5 | "time"
6 |
7 | "com.lc.go.codepush/server/config"
8 | "gorm.io/driver/mysql"
9 | "gorm.io/gorm"
10 | "gorm.io/gorm/logger"
11 | )
12 |
13 | var ormDB *gorm.DB
14 |
15 | func GetUserDB() (odb *gorm.DB, err error) {
16 | if ormDB != nil {
17 | odb = ormDB
18 | return
19 | }
20 | dbConfig := config.GetConfig().DBUser
21 | dsnSource := dbConfig.Write.UserName + ":" + dbConfig.Write.Password + "@tcp(" + dbConfig.Write.Host + ":" + strconv.Itoa(int(dbConfig.Write.Port)) + ")/" + dbConfig.Write.DBname + "?charset=utf8mb4&parseTime=True&loc=Local"
22 |
23 | db, err := gorm.Open(mysql.Open(dsnSource), &gorm.Config{
24 | Logger: logger.Default.LogMode(logger.Error),
25 | })
26 | if err != nil {
27 | return
28 | }
29 | sqlDb, err := db.DB()
30 | if err != nil {
31 | return
32 | }
33 | sqlDb.SetMaxIdleConns(int(dbConfig.MaxIdleConns))
34 | sqlDb.SetMaxOpenConns(int(dbConfig.MaxOpenConns))
35 | sqlDb.SetConnMaxIdleTime(time.Duration(dbConfig.MaxIdleConns))
36 |
37 | ormDB = db
38 | odb = ormDB
39 | return
40 | }
41 |
--------------------------------------------------------------------------------
/db/redis/redis.go:
--------------------------------------------------------------------------------
1 | package redis
2 |
3 | import (
4 | "context"
5 | "encoding/json"
6 | "fmt"
7 | "log"
8 | "strconv"
9 | "time"
10 |
11 | "com.lc.go.codepush/server/config"
12 | "github.com/redis/go-redis/v9"
13 | )
14 |
15 | var redisDB *redis.Client
16 | var ctx context.Context = context.Background()
17 |
18 | func GetRedis() (redisD *redis.Client, err error) {
19 | if redisDB != nil {
20 | redisD = redisDB
21 | return
22 | }
23 | redisConfig := config.GetConfig().Redis
24 | redisDB = redis.NewClient(&redis.Options{
25 | Addr: redisConfig.Host + ":" + strconv.Itoa(int(redisConfig.Port)),
26 | Username: redisConfig.UserName,
27 | Password: redisConfig.Password,
28 | DB: int(redisConfig.DBIndex),
29 | })
30 | redisD = redisDB
31 | return
32 | }
33 |
34 | func SetRedisObj(key string, obj any, duration time.Duration) {
35 | redis, _ := GetRedis()
36 | jData, _ := json.Marshal(obj)
37 | status := redis.Set(ctx, key, string(jData), duration)
38 | if err := status.Err(); err != nil {
39 | fmt.Println(err.Error())
40 | }
41 | }
42 |
43 | func DelRedisObj(key string) {
44 | redis, _ := GetRedis()
45 |
46 | iter := redis.Scan(ctx, 0, key, 0).Iterator()
47 | for iter.Next(ctx) {
48 | err := redis.Del(ctx, iter.Val()).Err()
49 | if err != nil {
50 | panic("Redis error:" + err.Error())
51 | }
52 | }
53 | if err := iter.Err(); err != nil {
54 | panic("Redis error:" + err.Error())
55 | }
56 | }
57 |
58 | func GetRedisObj[T any](key string) *T {
59 |
60 | redis, _ := GetRedis()
61 | status := redis.Get(ctx, key)
62 | if err := status.Err(); err != nil {
63 | log.Println(err.Error())
64 | return nil
65 | }
66 | var obj T
67 | err := json.Unmarshal([]byte(status.Val()), &obj)
68 | if err != nil {
69 | panic("Redis error:" + err.Error())
70 | }
71 | return &obj
72 | }
73 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module com.lc.go.codepush/server
2 |
3 | go 1.21.5
4 |
5 | require gorm.io/driver/mysql v1.5.6
6 |
7 | require (
8 | github.com/bytedance/sonic v1.11.3 // indirect
9 | github.com/cespare/xxhash/v2 v2.2.0 // indirect
10 | github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
11 | github.com/chenzhuoyu/iasm v0.9.1 // indirect
12 | github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
13 | github.com/gabriel-vasile/mimetype v1.4.3 // indirect
14 | github.com/gin-contrib/sse v0.1.0 // indirect
15 | github.com/go-playground/locales v0.14.1 // indirect
16 | github.com/go-playground/universal-translator v0.18.1 // indirect
17 | github.com/go-playground/validator/v10 v10.19.0 // indirect
18 | github.com/goccy/go-json v0.10.2 // indirect
19 | github.com/hashicorp/errwrap v1.1.0 // indirect
20 | github.com/hashicorp/go-multierror v1.1.1 // indirect
21 | github.com/jlaffaye/ftp v0.2.0 // indirect
22 | github.com/jmespath/go-jmespath v0.4.0 // indirect
23 | github.com/json-iterator/go v1.1.12 // indirect
24 | github.com/klauspost/cpuid/v2 v2.2.7 // indirect
25 | github.com/leodido/go-urn v1.4.0 // indirect
26 | github.com/mattn/go-isatty v0.0.20 // indirect
27 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
28 | github.com/modern-go/reflect2 v1.0.2 // indirect
29 | github.com/pelletier/go-toml/v2 v2.2.0 // indirect
30 | github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
31 | github.com/ugorji/go/codec v1.2.12 // indirect
32 | golang.org/x/arch v0.7.0 // indirect
33 | golang.org/x/crypto v0.21.0 // indirect
34 | golang.org/x/net v0.22.0 // indirect
35 | golang.org/x/sys v0.18.0 // indirect
36 | golang.org/x/text v0.14.0 // indirect
37 | google.golang.org/protobuf v1.33.0 // indirect
38 | gopkg.in/yaml.v3 v3.0.1 // indirect
39 | )
40 |
41 | require (
42 | github.com/aws/aws-sdk-go v1.51.24
43 | github.com/gin-contrib/gzip v1.0.0
44 | github.com/gin-gonic/gin v1.9.1
45 | github.com/go-sql-driver/mysql v1.7.0 // indirect
46 | github.com/google/uuid v1.6.0
47 | github.com/jinzhu/inflection v1.0.0 // indirect
48 | github.com/jinzhu/now v1.1.5 // indirect
49 | github.com/redis/go-redis/v9 v9.5.1
50 | gorm.io/gorm v1.25.9 // indirect
51 | )
52 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | github.com/aws/aws-sdk-go v1.51.24 h1:nwL5MaommPkwb7Ixk24eWkdx5HY4of1gD10kFFVAl6A=
2 | github.com/aws/aws-sdk-go v1.51.24/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk=
3 | github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
4 | github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s=
5 | github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
6 | github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM=
7 | github.com/bytedance/sonic v1.11.3 h1:jRN+yEjakWh8aK5FzrciUHG8OFXK+4/KrAX/ysEtHAA=
8 | github.com/bytedance/sonic v1.11.3/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4=
9 | github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
10 | github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
11 | github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
12 | github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
13 | github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
14 | github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0=
15 | github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA=
16 | github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog=
17 | github.com/chenzhuoyu/iasm v0.9.1 h1:tUHQJXo3NhBqw6s33wkGn9SP3bvrWLdlVIJ3hQBL7P0=
18 | github.com/chenzhuoyu/iasm v0.9.1/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog=
19 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
20 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
21 | github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
22 | github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
23 | github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
24 | github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
25 | github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
26 | github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
27 | github.com/gin-contrib/gzip v1.0.0 h1:UKN586Po/92IDX6ie5CWLgMI81obiIp5nSP85T3wlTk=
28 | github.com/gin-contrib/gzip v1.0.0/go.mod h1:CtG7tQrPB3vIBo6Gat9FVUsis+1emjvQqd66ME5TdnE=
29 | github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
30 | github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
31 | github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
32 | github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
33 | github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
34 | github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
35 | github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
36 | github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
37 | github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js=
38 | github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
39 | github.com/go-playground/validator/v10 v10.19.0 h1:ol+5Fu+cSq9JD7SoSqe04GMI92cbn0+wvQ3bZ8b/AU4=
40 | github.com/go-playground/validator/v10 v10.19.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
41 | github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc=
42 | github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
43 | github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
44 | github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
45 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
46 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
47 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
48 | github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
49 | github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
50 | github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
51 | github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
52 | github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
53 | github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
54 | github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
55 | github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
56 | github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
57 | github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
58 | github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
59 | github.com/jlaffaye/ftp v0.2.0 h1:lXNvW7cBu7R/68bknOX3MrRIIqZ61zELs1P2RAiA3lg=
60 | github.com/jlaffaye/ftp v0.2.0/go.mod h1:is2Ds5qkhceAPy2xD6RLI6hmp/qysSoymZ+Z2uTnspI=
61 | github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
62 | github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
63 | github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
64 | github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
65 | github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
66 | github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
67 | github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk=
68 | github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
69 | github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
70 | github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
71 | github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
72 | github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
73 | github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
74 | github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
75 | github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
76 | github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
77 | github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
78 | github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
79 | github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
80 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
81 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
82 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
83 | github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
84 | github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
85 | github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ=
86 | github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=
87 | github.com/pelletier/go-toml/v2 v2.2.0 h1:QLgLl2yMN7N+ruc31VynXs1vhMZa7CeHHejIeBAsoHo=
88 | github.com/pelletier/go-toml/v2 v2.2.0/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
89 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
90 | github.com/redis/go-redis/v9 v9.5.1 h1:H1X4D3yHPaYrkL5X06Wh6xNVM/pX0Ft4RV0vMGvLBh8=
91 | github.com/redis/go-redis/v9 v9.5.1/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M=
92 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
93 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
94 | github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
95 | github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
96 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
97 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
98 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
99 | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
100 | github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
101 | github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
102 | github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
103 | github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
104 | github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
105 | github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
106 | github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
107 | github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
108 | github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
109 | github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
110 | github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
111 | golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
112 | golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=
113 | golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
114 | golang.org/x/arch v0.7.0 h1:pskyeJh/3AmoQ8CPE95vxHLqp1G1GfGNXTmcl9NEKTc=
115 | golang.org/x/arch v0.7.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
116 | golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
117 | golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
118 | golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
119 | golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
120 | golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
121 | golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
122 | golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
123 | golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
124 | golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
125 | golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
126 | golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
127 | golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
128 | golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
129 | golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
130 | golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
131 | golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
132 | golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
133 | golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
134 | golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
135 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
136 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
137 | google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
138 | google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
139 | google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
140 | google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
141 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
142 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
143 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
144 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
145 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
146 | gorm.io/driver/mysql v1.5.6 h1:Ld4mkIickM+EliaQZQx3uOJDJHtrd70MxAUqWqlx3Y8=
147 | gorm.io/driver/mysql v1.5.6/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM=
148 | gorm.io/gorm v1.25.7 h1:VsD6acwRjz2zFxGO50gPO6AkNs7KKnvfzUjHQhZDz/A=
149 | gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
150 | gorm.io/gorm v1.25.9 h1:wct0gxZIELDk8+ZqF/MVnHLkA1rvYlBWUMv2EdsK1g8=
151 | gorm.io/gorm v1.25.9/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
152 | nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
153 | rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
154 |
--------------------------------------------------------------------------------
/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 |
6 | "com.lc.go.codepush/server/config"
7 | "com.lc.go.codepush/server/middleware"
8 | "com.lc.go.codepush/server/request"
9 |
10 | "github.com/gin-contrib/gzip"
11 |
12 | "github.com/gin-gonic/gin"
13 | )
14 |
15 | func main() {
16 | fmt.Println("code-push-server-go V1.0.5")
17 | // gin.SetMode(gin.ReleaseMode)
18 | g := gin.Default()
19 | g.Use(gzip.Gzip(gzip.DefaultCompression))
20 | g.Use(middleware.Recover)
21 | configs := config.GetConfig()
22 |
23 | // g.Static("/bundels", "bundels")
24 |
25 | g.GET("/v0.1/public/codepush/update_check", request.Client{}.CheckUpdate)
26 | g.POST("/v0.1/public/codepush/report_status/deploy", request.Client{}.ReportStatus)
27 | g.POST("/v0.1/public/codepush/report_status/download", request.Client{}.Download)
28 |
29 | apiGroup := g.Group(configs.UrlPrefix)
30 | {
31 | apiGroup.POST("/login", request.User{}.Login)
32 | }
33 | authApi := apiGroup.Use(middleware.CheckToken)
34 | {
35 | authApi.POST("/createApp", request.App{}.CreateApp)
36 | authApi.POST("/createDeployment", request.App{}.CreateDeployment)
37 | authApi.POST("/createBundle", request.App{}.CreateBundle)
38 | authApi.POST("/checkBundle", request.App{}.CheckBundle)
39 | authApi.POST("/delApp", request.App{}.DelApp)
40 | authApi.POST("/delDeployment", request.App{}.DelDeployment)
41 | authApi.POST("/lsDeployment", request.App{}.LsDeployment)
42 | authApi.GET("/lsApp", request.App{}.LsApp)
43 | authApi.POST("/uploadBundle", request.App{}.UploadBundle)
44 | authApi.POST("/rollback", request.App{}.Rollback)
45 | authApi.POST("/changePassword", request.User{}.ChangePassword)
46 | }
47 |
48 | g.Run(configs.Port)
49 | }
50 |
--------------------------------------------------------------------------------
/middleware/middleware.go:
--------------------------------------------------------------------------------
1 | package middleware
2 |
3 | import (
4 | "fmt"
5 | "log"
6 | "net/http"
7 | "reflect"
8 |
9 | "com.lc.go.codepush/server/model"
10 | "com.lc.go.codepush/server/model/constants"
11 | "com.lc.go.codepush/server/utils"
12 | "github.com/gin-gonic/gin"
13 | )
14 |
15 | // 檢查token
16 | func CheckToken(ctx *gin.Context) {
17 | var token, _ = ctx.Cookie("token")
18 | if token == "" {
19 | token = ctx.GetHeader("token")
20 | }
21 |
22 | if token == "" {
23 | log.Panic("Token can't null")
24 | }
25 |
26 | tokenNow := model.GetOne[model.Token]("token=?", token)
27 |
28 | if *utils.GetTimeNow() > *tokenNow.ExpireTime || *tokenNow.Del {
29 | ctx.JSON(http.StatusInternalServerError, gin.H{
30 | "code": 1100,
31 | "msg": "Token expire",
32 | })
33 | ctx.Abort()
34 | } else {
35 | if (tokenNow != nil && tokenNow.Del != nil && *tokenNow.Del) || tokenNow == nil {
36 | ctx.JSON(http.StatusInternalServerError, gin.H{
37 | "code": 1100,
38 | "msg": "Token expire",
39 | })
40 | ctx.Abort()
41 | }
42 | }
43 |
44 | ctx.Set(constants.GIN_USER_ID, *tokenNow.Uid)
45 | }
46 |
47 | // 異常處理
48 | func Recover(c *gin.Context) {
49 | c.Writer.Header().Add("Access-Control-Allow-Origin", "*")
50 | c.Writer.Header().Add("Access-Control-Allow-Methods", "POST, GET, OPTIONS")
51 | c.Writer.Header().Add("Access-Control-Allow-Headers", "*")
52 | lang := c.GetHeader("Accept-Language")
53 | c.Set(constants.GIN_LANG, lang)
54 | // 加载defer异常处理
55 | defer func() {
56 | if err := recover(); err != nil {
57 | c.Writer.WriteHeader(http.StatusInternalServerError)
58 | log.Printf("Error:%s", err)
59 | // 返回统一的Json风格
60 | var msgStr string
61 | if fmt.Sprint(reflect.TypeOf(err)) == "string" {
62 | msgStr = fmt.Sprint(err)
63 | } else {
64 | msgStr = "system error"
65 | }
66 | c.JSON(http.StatusInternalServerError, gin.H{
67 | "code": 500,
68 | "msg": msgStr,
69 | "success": false,
70 | })
71 | //终止后续操作
72 | c.Abort()
73 | }
74 | }()
75 | if c.Request.Method == "OPTIONS" {
76 | c.Writer.WriteHeader(http.StatusNoContent)
77 | c.Abort()
78 | // return
79 | }
80 | //继续操作
81 | c.Next()
82 | }
83 |
--------------------------------------------------------------------------------
/model/app.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | type App struct {
4 | Id *int `gorm:"primarykey;autoIncrement;size:32"`
5 | Uid *int `json:"uid"`
6 | AppName *string `json:"appName"`
7 | OS *int `json:"os"`
8 | CreateTime *int64 `json:"createTime"`
9 | }
10 |
11 | func (App) GetAppByUidAndAppName(uid int, appName string) *App {
12 | var app *App
13 | err := userDb.Where("uid", uid).Where("app_name", appName).First(&app).Error
14 | if err != nil {
15 | return nil
16 | }
17 | return app
18 | }
19 |
--------------------------------------------------------------------------------
/model/base.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | import (
4 | "com.lc.go.codepush/server/db"
5 | "com.lc.go.codepush/server/model/constants"
6 | "gorm.io/gorm"
7 | )
8 |
9 | var userDb, _ = db.GetUserDB()
10 |
11 | func queryPage[T any](db *gorm.DB, page constants.PageBean) *constants.PageData[T] {
12 | var datas []T
13 | var total int64
14 | db.Count(&total)
15 | err := db.Offset(page.Page * page.Rows).Limit(page.Rows).Find(&datas).Error
16 | if err != nil {
17 | return nil
18 | }
19 | return &constants.PageData[T]{
20 | TotalCount: total,
21 | Data: datas,
22 | }
23 | }
24 |
25 | func Update[T any](saveData *T) {
26 | userDb.Updates(&saveData)
27 | }
28 |
29 | func Create[T any](saveData *T) (err error) {
30 | tx := userDb.Create(&saveData)
31 | return tx.Error
32 | }
33 |
34 | func GetOne[T any](sql string, arg any) *T {
35 | var t *T
36 | err := userDb.Select("*").Where(sql, arg).First(&t).Error
37 | if err != nil {
38 | return nil
39 | }
40 | return t
41 | }
42 |
43 | func GetList[T any](sql string, arg any) *[]T {
44 | var t *[]T
45 | err := userDb.Select("*").Where(sql, arg).Find(&t).Error
46 | if err != nil {
47 | return nil
48 | }
49 | return t
50 | }
51 |
52 | func Delete[T any](deleteData T) error {
53 | return userDb.Delete(deleteData).Error
54 | }
55 |
56 | func DeleteWhere(query string, args string, deleteData any) error {
57 | return userDb.Where(query, args).Delete(deleteData).Error
58 | }
59 |
--------------------------------------------------------------------------------
/model/constants/constants.go:
--------------------------------------------------------------------------------
1 | package constants
2 |
3 | const (
4 | GIN_USER_ID = "GIN_USER_ID"
5 | GIN_LANG = "LANG"
6 | )
7 | const (
8 | REDIS_TOKEN_INFO = "TOKEN:"
9 | REDIS_UPDATE_INFO = "UPDATE_INFO:"
10 | )
11 |
12 | const (
13 | CONFIG_LOGIN_VERIFICATION = "CONFIG_LOGIN_VERIFICATION"
14 | CONFIG_REGISTER_VERIFICATION = "CONFIG_REGISTER_VERIFICATION"
15 | )
16 |
17 | type ErrObj struct {
18 | Code int `json:"code"`
19 | Msg string `json:"msg"`
20 | }
21 |
22 | type PageData[T any] struct {
23 | Data []T `json:"data"`
24 | TotalCount int64 `json:"totalCount"`
25 | }
26 |
27 | type PageBean struct {
28 | Page int `json:"page"`
29 | Rows int `json:"rows"`
30 | }
31 |
32 | func (PageBean) GetNew() PageBean {
33 | return PageBean{Rows: 10}
34 | }
35 |
--------------------------------------------------------------------------------
/model/constants/token_info.go:
--------------------------------------------------------------------------------
1 | package constants
2 |
3 | type TokenInfo struct {
4 | Uid *int `json:"uid"`
5 | UserName *string `json:"userName"`
6 | Token *string `json:"token"`
7 | Money *int64 `json:"money"`
8 | VipTime *int64 `json:"vipTime"`
9 | // PlatformId int
10 | }
11 |
--------------------------------------------------------------------------------
/model/deployment.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | type Deployment struct {
4 | Id *int `gorm:"primarykey;autoIncrement;size:32"`
5 | AppId *int `json:"appId"`
6 | Name *string `json:"name"`
7 | Key *string `json:"key"`
8 | VersionId *int `json:"versionId"`
9 | UpdateTime *int64 `json:"updateTime"`
10 | CreateTime *int64 `json:"createTime"`
11 | }
12 |
13 | func (Deployment) TableName() string {
14 | return "deployment"
15 | }
16 |
17 | func (Deployment) GetByAppidAndName(appId int, name string) *Deployment {
18 | var deployment *Deployment
19 | err := userDb.Where("app_id", appId).Where("name", name).First(&deployment).Error
20 | if err != nil {
21 | return nil
22 | }
23 | return deployment
24 | }
25 |
26 | func (Deployment) GetByAppids(appId int) *[]Deployment {
27 | var deployment *[]Deployment
28 | err := userDb.Where("app_id", appId).Find(&deployment).Error
29 | if err != nil {
30 | return nil
31 | }
32 | return deployment
33 | }
34 |
--------------------------------------------------------------------------------
/model/deploymentVersion.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | type DeploymentVersion struct {
4 | Id *int `gorm:"primarykey;autoIncrement;size:32"`
5 | DeploymentId *int `json:"deploymentId"`
6 | AppVersion *string `json:"appVersion"`
7 | VersionNum *int64 `json:"version_num"`
8 | CurrentPackage *int `json:"currentPackage"`
9 | UpdateTime *int64 `json:"updateTime"`
10 | CreateTime *int64 `json:"createTime"`
11 | }
12 |
13 | func (DeploymentVersion) TableName() string {
14 | return "deployment_version"
15 | }
16 |
17 | func (DeploymentVersion) GetByKeyDeploymentIdAndVersion(deploymentId int, version string) *DeploymentVersion {
18 | var deploymentVersion *DeploymentVersion
19 | err := userDb.Where("deployment_id", deploymentId).Where("app_version", version).First(&deploymentVersion).Error
20 | if err != nil {
21 | return nil
22 | }
23 | return deploymentVersion
24 | }
25 |
26 | func (DeploymentVersion) GetNewVersionByKeyDeploymentId(deploymentId int) *DeploymentVersion {
27 | var deploymentVersion *DeploymentVersion
28 | err := userDb.Where("deployment_id", deploymentId).Order("version_num desc").First(&deploymentVersion).Error
29 | if err != nil {
30 | return nil
31 | }
32 | return deploymentVersion
33 | }
34 |
35 | func (DeploymentVersion) UpdateCurrentPackage(id int, pid *int) {
36 | userDb.Raw("update deployment_version set current_package=? where id=?", pid, id).Scan(&DeploymentVersion{})
37 | }
38 |
--------------------------------------------------------------------------------
/model/package.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | type Package struct {
4 | Id *int `gorm:"primarykey;autoIncrement;size:32"`
5 | DeploymentId *int `json:"deploymentId"`
6 | DeploymentVersionId *int `json:"deploymentVersionId"`
7 | Size *int64 `json:"size"`
8 | Hash *string `json:"hash"`
9 | Download *string `json:"download"`
10 | Active *int `json:"active"`
11 | Failed *int `json:"failed"`
12 | Installed *int `json:"installed"`
13 | CreateTime *int64 `json:"create_time"`
14 | Description *string `json:"description"`
15 | }
16 |
17 | func (Package) TableName() string {
18 | return "package"
19 | }
20 |
21 | func (Package) AddActive(pid int) {
22 | userDb.Raw("update package set active=active+1 where id=?", pid).Scan(&Package{})
23 | }
24 |
25 | func (Package) AddFailed(pid int) {
26 | userDb.Raw("update package set failed=failed+1 where id=?", pid).Scan(&Package{})
27 | }
28 |
29 | func (Package) AddInstalled(pid int) {
30 | userDb.Raw("update package set installed=installed+1 where id=?", pid).Scan(&Package{})
31 | }
32 |
33 | func (Package) GetRollbackPack(deploymentId int, lastPakcId int, deploymentVersionId int) *Package {
34 | var lastPackage *Package
35 | err := userDb.Where("deployment_id=?", deploymentId).Where("id", lastPakcId).Where("deployment_version_id", deploymentVersionId).Order("id desc").First(&lastPackage).Error
36 | if err != nil {
37 | return nil
38 | }
39 | return lastPackage
40 | }
41 |
--------------------------------------------------------------------------------
/model/token.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | type Token struct {
4 | Id *int `gorm:"primarykey;autoIncrement;size:32"`
5 | Uid *int `json:"uid"`
6 | Token *string `json:"token"`
7 | ExpireTime *int64 `json:"expireTime"`
8 | Del *bool `json:"del"`
9 | }
10 |
11 | func (Token) TableName() string {
12 | return "token"
13 | }
14 |
--------------------------------------------------------------------------------
/model/user.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | type User struct {
4 | Id *int `gorm:"primarykey;autoIncrement;size:32"`
5 | UserName *string `gorm:"size:200" json:"userName"`
6 | Password *string `gorm:"size:45" json:"-"`
7 | }
8 |
9 | func (User) TableName() string {
10 | return "users"
11 | }
12 |
13 | func (User) ChangePassword(uid int, password string) error {
14 | return userDb.Raw("update users set password=? where id=?", password, uid).Scan(&User{}).Error
15 | }
16 |
--------------------------------------------------------------------------------
/request/app.go:
--------------------------------------------------------------------------------
1 | package request
2 |
3 | import (
4 | "bytes"
5 | "log"
6 | "net/http"
7 | "os"
8 |
9 | "com.lc.go.codepush/server/config"
10 | "com.lc.go.codepush/server/db"
11 | "com.lc.go.codepush/server/db/redis"
12 | "com.lc.go.codepush/server/model"
13 | "com.lc.go.codepush/server/model/constants"
14 | "com.lc.go.codepush/server/utils"
15 | "github.com/aws/aws-sdk-go/aws"
16 | "github.com/aws/aws-sdk-go/aws/credentials"
17 | "github.com/aws/aws-sdk-go/aws/session"
18 | "github.com/aws/aws-sdk-go/service/s3"
19 | "github.com/gin-gonic/gin"
20 | "github.com/gin-gonic/gin/binding"
21 | "github.com/google/uuid"
22 | "github.com/jlaffaye/ftp"
23 | "gorm.io/gorm"
24 | )
25 |
26 | type App struct{}
27 |
28 | type createAppReq struct {
29 | AppName *string `json:"appName" binding:"required"`
30 | OS *int `json:"os" binding:"required"`
31 | }
32 |
33 | func (App) CreateApp(ctx *gin.Context) {
34 | createAppInfo := createAppReq{}
35 | if err := ctx.ShouldBindBodyWith(&createAppInfo, binding.JSON); err == nil {
36 | uid := ctx.MustGet(constants.GIN_USER_ID).(int)
37 | oldApp := model.App{}.GetAppByUidAndAppName(uid, *createAppInfo.AppName)
38 | if oldApp != nil {
39 | log.Panic("AppName " + *createAppInfo.AppName + " exist")
40 | }
41 | if *createAppInfo.OS != 1 && *createAppInfo.OS != 2 {
42 | log.Panic("OS error")
43 | }
44 | newApp := model.App{
45 | Uid: &uid,
46 | AppName: createAppInfo.AppName,
47 | OS: createAppInfo.OS,
48 | CreateTime: utils.GetTimeNow(),
49 | }
50 | model.Create[model.App](&newApp)
51 | ctx.JSON(http.StatusOK, gin.H{
52 | "success": true,
53 | })
54 | } else {
55 | log.Panic(err.Error())
56 | }
57 | }
58 |
59 | type createBundleReq struct {
60 | AppName *string `json:"appName" binding:"required"`
61 | Deployment *string `json:"deployment" binding:"required"`
62 | DownloadUrl *string `json:"downloadUrl" binding:"required"`
63 | Description *string `json:"description"`
64 | Version *string `json:"version" binding:"required"`
65 | Size *int64 `json:"size" binding:"required"`
66 | Hash *string `json:"hash" binding:"required"`
67 | }
68 |
69 | func (App) CreateBundle(ctx *gin.Context) {
70 | createBundleReq := createBundleReq{}
71 | if err := ctx.ShouldBindBodyWith(&createBundleReq, binding.JSON); err == nil {
72 | uid := ctx.MustGet(constants.GIN_USER_ID).(int)
73 |
74 | app := model.App{}.GetAppByUidAndAppName(uid, *createBundleReq.AppName)
75 | if app == nil {
76 | log.Panic("App not found")
77 | }
78 | deployment := model.Deployment{}.GetByAppidAndName(*app.Id, *createBundleReq.Deployment)
79 | if deployment == nil {
80 | log.Panic("Deployment " + *createBundleReq.Deployment + " not found")
81 | }
82 | deploymentVersion := model.DeploymentVersion{}.GetByKeyDeploymentIdAndVersion(*deployment.Id, *createBundleReq.Version)
83 | if deploymentVersion == nil {
84 | versionNum := utils.FormatVersionStr(*createBundleReq.Version)
85 | deploymentVersion = &model.DeploymentVersion{
86 | DeploymentId: deployment.Id,
87 | AppVersion: createBundleReq.Version,
88 | VersionNum: &versionNum,
89 | CreateTime: utils.GetTimeNow(),
90 | }
91 | model.Create[model.DeploymentVersion](deploymentVersion)
92 |
93 | if deployment.VersionId != nil {
94 | deploymentVersionOld := model.GetOne[model.DeploymentVersion]("id=?", *deployment.VersionId)
95 | if utils.FormatVersionStr(*deploymentVersionOld.AppVersion) < utils.FormatVersionStr(*createBundleReq.Version) {
96 | deployment.VersionId = deploymentVersion.Id
97 | deployment.UpdateTime = utils.GetTimeNow()
98 | model.Update[model.Deployment](deployment)
99 | }
100 | } else {
101 | deployment.VersionId = deploymentVersion.Id
102 | deployment.UpdateTime = utils.GetTimeNow()
103 | model.Update[model.Deployment](deployment)
104 | }
105 | } else {
106 | nowPack := model.GetOne[model.Package]("id=?", deploymentVersion.CurrentPackage)
107 | if nowPack != nil && *nowPack.Hash == *createBundleReq.Hash {
108 | log.Panic("Upload package no modification")
109 | }
110 | }
111 | // uuid, _ := uuid.NewUUID()
112 | // hash := uuid.String()
113 | newPackage := model.Package{
114 | DeploymentId: deployment.Id,
115 | DeploymentVersionId: deploymentVersion.Id,
116 | Size: createBundleReq.Size,
117 | Hash: createBundleReq.Hash,
118 | Download: createBundleReq.DownloadUrl,
119 | Description: createBundleReq.Description,
120 | Active: utils.CreateInt(0),
121 | Installed: utils.CreateInt(0),
122 | Failed: utils.CreateInt(0),
123 | CreateTime: utils.GetTimeNow(),
124 | }
125 | model.Create[model.Package](&newPackage)
126 | deploymentVersion.CurrentPackage = newPackage.Id
127 | deploymentVersion.UpdateTime = utils.GetTimeNow()
128 | model.Update[model.DeploymentVersion](deploymentVersion)
129 | redis.DelRedisObj(constants.REDIS_UPDATE_INFO + *deployment.Key + "*")
130 | } else {
131 | log.Panic(err.Error())
132 | }
133 | }
134 |
135 | type createDeploymentInfo struct {
136 | AppName *string `json:"appName" binding:"required"`
137 | DeploymentName *string `json:"deploymentName" binding:"required"`
138 | }
139 |
140 | func (App) CreateDeployment(ctx *gin.Context) {
141 | createDeploymentInfo := createDeploymentInfo{}
142 | if err := ctx.ShouldBindBodyWith(&createDeploymentInfo, binding.JSON); err == nil {
143 | uid := ctx.MustGet(constants.GIN_USER_ID).(int)
144 | app := model.App{}.GetAppByUidAndAppName(uid, *createDeploymentInfo.AppName)
145 | if app == nil {
146 | log.Panic("App not found")
147 | }
148 | deployment := model.Deployment{}.GetByAppidAndName(*app.Id, *createDeploymentInfo.DeploymentName)
149 | if deployment != nil {
150 | log.Panic("Deployment name " + *createDeploymentInfo.DeploymentName + " exist")
151 | }
152 | uuid, _ := uuid.NewUUID()
153 | key := uuid.String()
154 | newDeployment := model.Deployment{
155 | AppId: app.Id,
156 | Name: createDeploymentInfo.DeploymentName,
157 | Key: &key,
158 | CreateTime: utils.GetTimeNow(),
159 | }
160 | err := model.Create[model.Deployment](&newDeployment)
161 | if err != nil {
162 | log.Panic(err.Error())
163 | }
164 | ctx.JSON(http.StatusOK, gin.H{
165 | "name": createDeploymentInfo.DeploymentName,
166 | "key": key,
167 | })
168 | } else {
169 | log.Panic(err.Error())
170 | }
171 | }
172 | func (App) UploadBundle(ctx *gin.Context) {
173 | _, headers, err := ctx.Request.FormFile("file")
174 | if err != nil {
175 | log.Printf("Error when try to get file: %v", err)
176 | }
177 | file, err := headers.Open()
178 | if err != nil {
179 | log.Panic(err.Error())
180 | }
181 | defer file.Close()
182 | config := config.GetConfig()
183 |
184 | key := headers.Filename
185 |
186 | switch config.CodePush.FileLocal {
187 | case "local":
188 | exist := utils.Exists(config.CodePush.Local.SavePath)
189 | if !exist {
190 | err := os.MkdirAll(config.CodePush.Local.SavePath, 0777)
191 | if err != nil {
192 | log.Panic(err.Error())
193 | }
194 | }
195 | buf := new(bytes.Buffer)
196 | _, err := buf.ReadFrom(file)
197 | if err != nil {
198 | log.Panic(err.Error())
199 | }
200 | os.WriteFile(config.CodePush.Local.SavePath+"/"+key, buf.Bytes(), 0777)
201 | case "aws":
202 | s3Config := &aws.Config{
203 | Credentials: credentials.NewStaticCredentials(config.CodePush.Aws.KeyId, config.CodePush.Aws.Secret, ""),
204 | Endpoint: aws.String(config.CodePush.Aws.Endpoint),
205 | Region: aws.String(config.CodePush.Aws.Region),
206 | S3ForcePathStyle: aws.Bool(config.CodePush.Aws.S3ForcePathStyle),
207 | }
208 | newSession, _ := session.NewSession(s3Config)
209 |
210 | s3Client := s3.New(newSession)
211 |
212 | _, err = s3Client.PutObject(&s3.PutObjectInput{
213 | Body: file,
214 | Bucket: aws.String(config.CodePush.Aws.Bucket),
215 | Key: &key,
216 | })
217 | if err != nil {
218 | log.Panic(err.Error())
219 | }
220 | case "ftp":
221 | f, err := ftp.Dial(config.CodePush.Ftp.ServerUrl)
222 | if err != nil {
223 | log.Panic(err.Error())
224 | }
225 | err = f.Login(config.CodePush.Ftp.UserName, config.CodePush.Ftp.Password)
226 | if err != nil {
227 | log.Panic(err.Error())
228 | }
229 |
230 | err = f.Stor(key, file)
231 | if err != nil {
232 | log.Panic(err.Error())
233 | }
234 | if err := f.Quit(); err != nil {
235 | log.Panic(err.Error())
236 | }
237 |
238 | }
239 |
240 | ctx.JSON(http.StatusOK, gin.H{
241 | "success": true,
242 | })
243 | }
244 |
245 | type lsDeploymentReq struct {
246 | ShowKey *bool `json:"k" binding:"required"`
247 | AppName *string `json:"appName" binding:"required"`
248 | }
249 |
250 | type lsDeploymentInfo struct {
251 | AppName *string `json:"appName"`
252 | Deployments *[]deploymentInfo `json:"deployments"`
253 | }
254 |
255 | type deploymentInfo struct {
256 | DeploymentName *string `json:"deploymentName"`
257 | AppVersion *string `json:"appVersion"`
258 | Active *int `json:"active"`
259 | Failed *int `json:"failed"`
260 | Installed *int `json:"installed"`
261 | DeploymentKey *string `json:"deploymentKey"`
262 | }
263 |
264 | func (App) LsDeployment(ctx *gin.Context) {
265 | lsAppReq := lsDeploymentReq{}
266 | if err := ctx.ShouldBindBodyWith(&lsAppReq, binding.JSON); err == nil {
267 | uid := ctx.MustGet(constants.GIN_USER_ID).(int)
268 | app := model.App{}.GetAppByUidAndAppName(uid, *lsAppReq.AppName)
269 | if app == nil {
270 | log.Panic("App not found")
271 | }
272 | var deploymentInfos []deploymentInfo
273 | deployment := model.Deployment{}.GetByAppids(*app.Id)
274 |
275 | for _, v := range *deployment {
276 | var key *string
277 | if *lsAppReq.ShowKey {
278 | key = v.Key
279 | }
280 | deploymentInfo := deploymentInfo{
281 | DeploymentName: v.Name,
282 | DeploymentKey: key,
283 | }
284 | if v.VersionId != nil {
285 | deploymentVersion := model.GetOne[model.DeploymentVersion]("id=?", v.VersionId)
286 | deploymentInfo.AppVersion = deploymentVersion.AppVersion
287 | if deploymentVersion.CurrentPackage != nil {
288 | pack := model.GetOne[model.Package]("id=?", deploymentVersion.CurrentPackage)
289 | deploymentInfo.Active = pack.Active
290 | deploymentInfo.Failed = pack.Failed
291 | deploymentInfo.Installed = pack.Installed
292 | }
293 | }
294 |
295 | deploymentInfos = append(deploymentInfos, deploymentInfo)
296 | }
297 | lsAppInfo := lsDeploymentInfo{
298 | AppName: app.AppName,
299 | Deployments: &deploymentInfos,
300 | }
301 | ctx.JSON(http.StatusOK, lsAppInfo)
302 | } else {
303 | log.Panic(err.Error())
304 | }
305 | }
306 |
307 | func (App) LsApp(ctx *gin.Context) {
308 | uid := ctx.MustGet(constants.GIN_USER_ID).(int)
309 | apps := model.GetList[model.App]("uid=?", uid)
310 | if len(*apps) <= 0 {
311 | log.Panic("No app")
312 | }
313 | var appsRep []string
314 |
315 | for _, v := range *apps {
316 | appsRep = append(appsRep, *v.AppName)
317 | }
318 | ctx.JSON(http.StatusOK, appsRep)
319 | }
320 |
321 | type checkBundleReq struct {
322 | AppName *string `json:"appName" binding:"required"`
323 | Deployment *string `json:"deployment" binding:"required"`
324 | Version *string `json:"version" binding:"required"`
325 | }
326 |
327 | func (App) CheckBundle(ctx *gin.Context) {
328 | checkBundleReq := checkBundleReq{}
329 | if err := ctx.ShouldBindBodyWith(&checkBundleReq, binding.JSON); err == nil {
330 | uid := ctx.MustGet(constants.GIN_USER_ID).(int)
331 |
332 | app := model.App{}.GetAppByUidAndAppName(uid, *checkBundleReq.AppName)
333 | if app == nil {
334 | log.Panic("App not found")
335 | }
336 | deployment := model.Deployment{}.GetByAppidAndName(*app.Id, *checkBundleReq.Deployment)
337 | if deployment == nil {
338 | log.Panic("Deployment " + *checkBundleReq.Deployment + " not found")
339 | }
340 | var hash *string
341 | if deployment.VersionId != nil {
342 | deployment := model.DeploymentVersion{}.GetByKeyDeploymentIdAndVersion(*deployment.Id, *checkBundleReq.Version)
343 | if deployment != nil && deployment.CurrentPackage != nil {
344 | pack := model.GetOne[model.Package]("id", deployment.CurrentPackage)
345 | hash = pack.Hash
346 | }
347 | }
348 |
349 | ctx.JSON(http.StatusOK, gin.H{
350 | "appName": app.AppName,
351 | "os": app.OS,
352 | "hash": hash,
353 | })
354 | } else {
355 | log.Panic(err.Error())
356 | }
357 | }
358 |
359 | type delAppInfo struct {
360 | AppName *string `json:"appName" binding:"required"`
361 | }
362 |
363 | func (App) DelApp(ctx *gin.Context) {
364 | delAppInfo := delAppInfo{}
365 | if err := ctx.ShouldBindBodyWith(&delAppInfo, binding.JSON); err == nil {
366 | uid := ctx.MustGet(constants.GIN_USER_ID).(int)
367 |
368 | app := model.App{}.GetAppByUidAndAppName(uid, *delAppInfo.AppName)
369 | if app == nil {
370 | log.Panic("App not found")
371 | }
372 | deployment := model.Deployment{}.GetByAppids(*app.Id)
373 | if deployment != nil && len(*deployment) > 0 {
374 | log.Panic("App exist deployment,Delete the deployment first and then delete the app ")
375 | }
376 | model.Delete[model.App](model.App{Id: app.Id})
377 | ctx.JSON(http.StatusOK, gin.H{
378 | "success": true,
379 | })
380 | } else {
381 | log.Panic(err.Error())
382 | }
383 | }
384 |
385 | type delDeploymentInfo struct {
386 | AppName *string `json:"appName" binding:"required"`
387 | Deployment *string `json:"deployment" binding:"required"`
388 | }
389 |
390 | func (App) DelDeployment(ctx *gin.Context) {
391 | delDeploymentInfo := delDeploymentInfo{}
392 | if err := ctx.ShouldBindBodyWith(&delDeploymentInfo, binding.JSON); err == nil {
393 | uid := ctx.MustGet(constants.GIN_USER_ID).(int)
394 |
395 | app := model.App{}.GetAppByUidAndAppName(uid, *delDeploymentInfo.AppName)
396 | if app == nil {
397 | log.Panic("App not found")
398 | }
399 | deployment := model.Deployment{}.GetByAppidAndName(*app.Id, *delDeploymentInfo.Deployment)
400 | if deployment == nil {
401 | log.Panic("Deployment " + *delDeploymentInfo.Deployment + " not found")
402 | }
403 | userDb, _ := db.GetUserDB()
404 | err := userDb.Transaction(func(tx *gorm.DB) error {
405 | if err := tx.Delete(model.Deployment{Id: deployment.Id}).Error; err != nil {
406 | panic("DeleteError:" + err.Error())
407 | }
408 | if err := tx.Where("deployment_id", *deployment.Id).Delete(model.DeploymentVersion{}).Error; err != nil {
409 | panic("DeleteError:" + err.Error())
410 | }
411 | if err := tx.Where("deployment_id", *deployment.Id).Delete(model.Package{}).Error; err != nil {
412 | panic("DeleteError:" + err.Error())
413 | }
414 | return nil
415 | })
416 | if err != nil {
417 | panic("DeleteError:" + err.Error())
418 | }
419 |
420 | ctx.JSON(http.StatusOK, gin.H{
421 | "success": true,
422 | })
423 | } else {
424 | log.Panic(err.Error())
425 | }
426 | }
427 |
428 | type rollbackReq struct {
429 | AppName *string `json:"appName" binding:"required"`
430 | Deployment *string `json:"deployment" binding:"required"`
431 | Version *string `json:"version"`
432 | }
433 |
434 | func (App) Rollback(ctx *gin.Context) {
435 | rollbackReq := rollbackReq{}
436 | if err := ctx.ShouldBindBodyWith(&rollbackReq, binding.JSON); err == nil {
437 | uid := ctx.MustGet(constants.GIN_USER_ID).(int)
438 |
439 | app := model.App{}.GetAppByUidAndAppName(uid, *rollbackReq.AppName)
440 | if app == nil {
441 | log.Panic("App not found")
442 | }
443 | deployment := model.Deployment{}.GetByAppidAndName(*app.Id, *rollbackReq.Deployment)
444 | if deployment == nil {
445 | log.Panic("Deployment " + *rollbackReq.Deployment + " not found")
446 | }
447 |
448 | var deploymentVersion *model.DeploymentVersion
449 | if deployment.VersionId != nil {
450 | deploymentVersion = model.DeploymentVersion{}.GetByKeyDeploymentIdAndVersion(*deployment.Id, *rollbackReq.Version)
451 | }
452 | if deploymentVersion == nil {
453 | log.Panic("Version not found")
454 | }
455 | if deploymentVersion.CurrentPackage == nil {
456 | log.Panic("There is no upload package for the current version")
457 | }
458 | newPackage := model.Package{}.GetRollbackPack(*deployment.Id, *deploymentVersion.CurrentPackage, *deploymentVersion.Id)
459 |
460 | userDb, _ := db.GetUserDB()
461 | err := userDb.Transaction(func(tx *gorm.DB) error {
462 | if newPackage == nil {
463 | model.DeploymentVersion{}.UpdateCurrentPackage(*deploymentVersion.Id, nil)
464 | } else {
465 | model.DeploymentVersion{}.UpdateCurrentPackage(*deploymentVersion.Id, newPackage.Id)
466 | }
467 | return nil
468 | })
469 | if err != nil {
470 | panic("RollbackError:" + err.Error())
471 | }
472 |
473 | if newPackage != nil {
474 | ctx.JSON(http.StatusOK, gin.H{
475 | "Success": true,
476 | "Version": *deploymentVersion.AppVersion,
477 | "PackId": *newPackage.Id,
478 | "Size": *newPackage.Size,
479 | "Hash": *newPackage.Hash,
480 | "CreateTime": *newPackage.CreateTime,
481 | })
482 | } else {
483 | ctx.JSON(http.StatusOK, gin.H{
484 | "Success": true,
485 | "Version": *deploymentVersion.AppVersion,
486 | })
487 | }
488 | redis.DelRedisObj(constants.REDIS_UPDATE_INFO + *deployment.Key + "*")
489 | } else {
490 | log.Panic(err.Error())
491 | }
492 | }
493 |
--------------------------------------------------------------------------------
/request/client.go:
--------------------------------------------------------------------------------
1 | package request
2 |
3 | import (
4 | "log"
5 | "net/http"
6 | "strconv"
7 |
8 | "com.lc.go.codepush/server/config"
9 | "com.lc.go.codepush/server/db/redis"
10 | "com.lc.go.codepush/server/model"
11 | "com.lc.go.codepush/server/model/constants"
12 | "com.lc.go.codepush/server/utils"
13 | "github.com/gin-gonic/gin"
14 | )
15 |
16 | type Client struct{}
17 | type updateInfo struct {
18 | DownloadUrl string `json:"download_url"`
19 | Description string `json:"description"`
20 | IsAvailable bool `json:"is_available"`
21 | IsDisabled bool `json:"is_disabled"`
22 | TargetBinaryRange string `json:"target_binary_range"`
23 | PackageHash string `json:"package_hash"`
24 | Label string `json:"label"`
25 | PackageSize int64 `json:"package_size"`
26 | UpdateAppVersion bool `json:"update_app_version"`
27 | ShouldRunBinaryVersion bool `json:"should_run_binary_version"`
28 | IsMandatory bool `json:"is_mandatory"`
29 | }
30 | type updateInfoRedisInfo struct {
31 | updateInfo
32 | NewVersion string
33 | }
34 |
35 | func (Client) CheckUpdate(ctx *gin.Context) {
36 | deploymentKey := ctx.Query("deployment_key")
37 | appVersion := ctx.Query("app_version")
38 | packageHash := ctx.Query("package_hash")
39 | // label := ctx.Query("label")
40 | // clientUniqueId := ctx.Query("client_unique_id")
41 | redisKey := constants.REDIS_UPDATE_INFO + deploymentKey + ":" + appVersion
42 | updateInfoRedis := redis.GetRedisObj[updateInfoRedisInfo](redisKey)
43 | updateInfo := updateInfo{}
44 | config := config.GetConfig()
45 |
46 | if updateInfoRedis == nil {
47 | updateInfoRedis = &updateInfoRedisInfo{}
48 | deployment := model.GetOne[model.Deployment]("key", deploymentKey)
49 | if deployment == nil {
50 | log.Panic("Key error")
51 | }
52 | deploymentVersion := model.DeploymentVersion{}.GetByKeyDeploymentIdAndVersion(*deployment.Id, appVersion)
53 | if deploymentVersion != nil {
54 | if deploymentVersion.CurrentPackage != nil {
55 | packag := model.GetOne[model.Package]("id", deploymentVersion.CurrentPackage)
56 | if packag != nil {
57 | // && *packag.Hash != packageHash
58 | updateInfoRedis.TargetBinaryRange = *deploymentVersion.AppVersion
59 | updateInfoRedis.PackageHash = *packag.Hash
60 | updateInfoRedis.PackageSize = *packag.Size
61 | updateInfoRedis.IsAvailable = true
62 | updateInfoRedis.IsMandatory = true
63 | label := strconv.Itoa(*packag.Id)
64 | updateInfoRedis.Label = label
65 | updateInfoRedis.DownloadUrl = config.ResourceUrl + *packag.Download
66 | if packag.Description != nil {
67 | updateInfoRedis.Description = *packag.Description
68 | }
69 | }
70 | }
71 | }
72 | deploymentVersionNew := model.DeploymentVersion{}.GetNewVersionByKeyDeploymentId(*deployment.Id)
73 | if deploymentVersionNew != nil {
74 | updateInfoRedis.NewVersion = *deploymentVersionNew.AppVersion
75 | }
76 | redis.SetRedisObj(redisKey, updateInfoRedis, -1)
77 | }
78 | if updateInfoRedis.PackageHash != "" {
79 | if updateInfoRedis.PackageHash != packageHash && appVersion == updateInfoRedis.TargetBinaryRange {
80 | updateInfo.TargetBinaryRange = updateInfoRedis.TargetBinaryRange
81 | updateInfo.PackageHash = updateInfoRedis.PackageHash
82 | updateInfo.PackageSize = updateInfoRedis.PackageSize
83 | updateInfo.IsAvailable = true
84 | updateInfo.IsMandatory = true
85 | updateInfo.Label = updateInfoRedis.Label
86 | updateInfo.DownloadUrl = updateInfoRedis.DownloadUrl
87 | updateInfo.Description = updateInfoRedis.Description
88 | } else if updateInfoRedis.NewVersion != "" && appVersion != updateInfoRedis.NewVersion && utils.FormatVersionStr(appVersion) < utils.FormatVersionStr(updateInfoRedis.NewVersion) {
89 | updateInfo.TargetBinaryRange = updateInfoRedis.NewVersion
90 | updateInfo.UpdateAppVersion = true
91 | }
92 |
93 | } else if updateInfoRedis.NewVersion != "" && appVersion != updateInfoRedis.NewVersion && utils.FormatVersionStr(appVersion) < utils.FormatVersionStr(updateInfoRedis.NewVersion) {
94 | updateInfo.TargetBinaryRange = updateInfoRedis.NewVersion
95 | updateInfo.UpdateAppVersion = true
96 | }
97 |
98 | ctx.JSON(http.StatusOK, gin.H{
99 | "update_info": updateInfo,
100 | })
101 |
102 | }
103 |
104 | type reportStatuReq struct {
105 | AppVersion *string `json:"app_version"`
106 | DeploymentKey *string `json:"deployment_key"`
107 | ClientUniqueId *string `json:"client_unique_id"`
108 | Label *string `json:"label"`
109 | Status *string `json:"status"`
110 | PreviousLabelOrAppVersion *string `json:"previous_label_or_app_version"`
111 | PreviousDeploymentKey *string `json:"previous_deployment_key"`
112 | }
113 |
114 | func (Client) ReportStatus(ctx *gin.Context) {
115 | json := reportStatuReq{}
116 | ctx.BindJSON(&json)
117 | if json.Status != nil {
118 | pack := model.GetOne[model.Package]("id=?", json.Label)
119 | if pack != nil {
120 | if *json.Status == "DeploymentSucceeded" {
121 | model.Package{}.AddActive(*pack.Id)
122 | } else if *json.Status == "DeploymentFailed" {
123 | model.Package{}.AddFailed(*pack.Id)
124 | }
125 | }
126 |
127 | }
128 |
129 | ctx.String(http.StatusOK, "OK")
130 | }
131 |
132 | type downloadReq struct {
133 | ClientUniqueId *string `json:"client_unique_id"`
134 | DeploymentKey *string `json:"deployment_key"`
135 | Label *string `json:"label"`
136 | }
137 |
138 | func (Client) Download(ctx *gin.Context) {
139 | json := downloadReq{}
140 | ctx.BindJSON(&json)
141 | pack := model.GetOne[model.Package]("id=?", json.Label)
142 | if pack != nil {
143 | model.Package{}.AddInstalled(*pack.Id)
144 | }
145 | ctx.String(http.StatusOK, "OK")
146 | }
147 |
--------------------------------------------------------------------------------
/request/user.go:
--------------------------------------------------------------------------------
1 | package request
2 |
3 | import (
4 | "log"
5 | "net/http"
6 |
7 | "com.lc.go.codepush/server/config"
8 | "com.lc.go.codepush/server/model"
9 | "com.lc.go.codepush/server/model/constants"
10 | "com.lc.go.codepush/server/utils"
11 | "github.com/gin-gonic/gin"
12 | "github.com/gin-gonic/gin/binding"
13 | "github.com/google/uuid"
14 | )
15 |
16 | type User struct{}
17 |
18 | type loginUser struct {
19 | UserName *string `json:"userName" binding:"required"`
20 | Password *string `json:"password" binding:"required"`
21 | }
22 |
23 | func (User) Login(ctx *gin.Context) {
24 | loginUser := loginUser{}
25 | if err := ctx.ShouldBindBodyWith(&loginUser, binding.JSON); err == nil {
26 | user := model.GetOne[model.User]("user_name", &loginUser.UserName)
27 | if user == nil || *user.Password != *loginUser.Password {
28 | panic("UserName or Psssword error")
29 | }
30 | uuid, _ := uuid.NewUUID()
31 | timeNow := utils.GetTimeNow()
32 | expireTime := *timeNow + (config.GetConfig().TokenExpireTime * 24 * 60 * 60 * 1000)
33 | token := uuid.String()
34 | del := false
35 | tokenInfo := model.Token{
36 | Uid: user.Id,
37 | Token: &token,
38 | ExpireTime: &expireTime,
39 | Del: &del,
40 | }
41 | err := model.Create[model.Token](&tokenInfo)
42 | if err != nil {
43 | panic("create token error")
44 | }
45 | ctx.JSON(http.StatusOK, gin.H{
46 | "token": token,
47 | })
48 | } else {
49 | log.Panic(err.Error())
50 | }
51 | }
52 |
53 | type changePasswordReq struct {
54 | Password *string `json:"password" binding:"required"`
55 | }
56 |
57 | func (User) ChangePassword(ctx *gin.Context) {
58 | req := changePasswordReq{}
59 | if err := ctx.ShouldBindBodyWith(&req, binding.JSON); err == nil {
60 | uid := ctx.MustGet(constants.GIN_USER_ID).(int)
61 | err := model.User{}.ChangePassword(uid, *req.Password)
62 | if err != nil {
63 | panic(err.Error())
64 | }
65 | ctx.JSON(http.StatusOK, gin.H{
66 | "success": true,
67 | })
68 | } else {
69 | log.Panic(err.Error())
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/utils/utils.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "log"
5 | "os"
6 | "sort"
7 | "strconv"
8 | "strings"
9 | "time"
10 | )
11 |
12 | func GetTimeNow() *int64 {
13 | t := time.Now().UnixMilli()
14 | return &t
15 | }
16 |
17 | func CreateInt(num int) *int {
18 | return &num
19 | }
20 |
21 | func Exists(path string) bool {
22 | _, err := os.Stat(path) //os.Stat获取文件信息
23 | if err != nil {
24 | return os.IsExist(err)
25 | }
26 | return true
27 | }
28 |
29 | func FormatVersionStr(v string) int64 {
30 | vs := strings.Split(v, ".")
31 | if len(vs) <= 0 {
32 | log.Panic("Version str error")
33 | }
34 | var vNum int64
35 | ReverseArr(vs)
36 | for index, v := range vs {
37 | num, err := strconv.ParseInt(v, 10, 64)
38 | if err != nil {
39 | log.Panic(err.Error())
40 | }
41 | for i := 0; i < index; i++ {
42 | num = num * 100
43 | }
44 | vNum += num
45 | }
46 | return vNum
47 | }
48 | func ReverseArr(s interface{}) {
49 | sort.SliceStable(s, func(i, j int) bool {
50 | return true
51 | })
52 | }
53 |
--------------------------------------------------------------------------------