Support downloading resources from CDN server

Signed-off-by: Yuan Si <do4suki@gmail.com>
This commit is contained in:
2023-04-10 05:35:13 +08:00
parent 8a69a9391b
commit 0fcb44dbd4
10 changed files with 464 additions and 10 deletions
BIN
View File
Binary file not shown.
+2
View File
@@ -10,3 +10,5 @@ log:
log_save: true
leveldb:
data_path: ./data/honoka-chan.db
cdn:
cdn_url: http://192.168.1.12:8081/static
+8
View File
@@ -18,6 +18,7 @@ type AppConfigs struct {
Server ServerConfigs `yaml:"server"`
Log LogConfigs `yaml:"log"`
LevelDb LevelDbConfigs `yaml:"leveldb"`
Cdn CdnConfigs `yaml:"cdn"`
}
type ServerConfigs struct {
@@ -37,6 +38,10 @@ type LevelDbConfigs struct {
DataPath string `yaml:"data_path"`
}
type CdnConfigs struct {
CdnUrl string `yaml:"cdn_url"`
}
func DefaultConfigs() *AppConfigs {
return &AppConfigs{
AppName: "LL! SIF Private Server",
@@ -54,6 +59,9 @@ func DefaultConfigs() *AppConfigs {
LevelDb: LevelDbConfigs{
DataPath: "./data/honoka-chan.db",
},
Cdn: CdnConfigs{
CdnUrl: "",
},
}
}
+208 -9
View File
@@ -1,25 +1,28 @@
package handler
import (
"database/sql"
"encoding/base64"
"encoding/json"
"fmt"
"honoka-chan/database"
"honoka-chan/encrypt"
"honoka-chan/model"
"honoka-chan/utils"
"net/http"
"time"
"github.com/gin-gonic/gin"
_ "github.com/mattn/go-sqlite3"
)
type DownloadResp struct {
ResponseData []interface{} `json:"response_data"`
ReleaseInfo []interface{} `json:"release_info"`
StatusCode int `json:"status_code"`
}
func DownloadAdditionalHandler(ctx *gin.Context) {
db, err := sql.Open("sqlite3", "assets/main.db")
if err != nil {
panic(err)
}
defer db.Close()
func DownloadBatchHandler(ctx *gin.Context) {
reqTime := time.Now().Unix()
authorizeStr := ctx.Request.Header["Authorize"]
@@ -51,8 +54,121 @@ func DownloadBatchHandler(ctx *gin.Context) {
newAuthorizeStr := fmt.Sprintf("consumerKey=lovelive_test&timeStamp=%d&version=1.1&token=%s&nonce=%d&user_id=%s&requestTimeStamp=%d", respTime, authToken, nonce, userId[0], reqTime)
// fmt.Println(newAuthorizeStr)
batchResp := DownloadResp{
ResponseData: []interface{}{},
downloadReq := model.AdditionalReq{}
if err := json.Unmarshal([]byte(ctx.PostForm("request_data")), &downloadReq); err != nil {
panic(err)
}
pkgList := []model.AdditionalResult{}
if CdnUrl != "" {
pkgType, pkgId := downloadReq.PackageType, downloadReq.PackageID
stmt, err := db.Prepare("SELECT pkg_order,pkg_size FROM download_db WHERE pkg_type = ? AND pkg_id = ? ORDER BY pkg_order ASC")
if err != nil {
panic(err)
}
rows, err := stmt.Query(pkgType, pkgId)
if err != nil {
panic(err)
}
for rows.Next() {
var pkgOrder, pkgSize int
err = rows.Scan(&pkgOrder, &pkgSize)
if err != nil {
panic(err)
}
pkgList = append(pkgList, model.AdditionalResult{
Size: pkgSize,
URL: fmt.Sprintf("%s/%d_%d_%d.zip", CdnUrl, pkgType, pkgId, pkgOrder),
})
}
}
addResp := model.AdditionalResp{
ResponseData: pkgList,
ReleaseInfo: []interface{}{},
StatusCode: 200,
}
resp, err := json.Marshal(addResp)
if err != nil {
panic(err)
}
// fmt.Println(string(resp))
xms := encrypt.RSA_Sign_SHA1(resp, "privatekey.pem")
xms64 := base64.RawStdEncoding.EncodeToString(xms)
ctx.Header("user_id", userId[0])
ctx.Header("authorize", newAuthorizeStr)
ctx.Header("X-Message-Sign", xms64)
ctx.String(http.StatusOK, string(resp))
}
func DownloadBatchHandler(ctx *gin.Context) {
db, err := sql.Open("sqlite3", "assets/main.db")
if err != nil {
panic(err)
}
defer db.Close()
reqTime := time.Now().Unix()
authorizeStr := ctx.Request.Header["Authorize"]
authToken, err := utils.GetAuthorizeToken(authorizeStr)
if err != nil {
ctx.String(http.StatusForbidden, "Fuck you!")
return
}
userId := ctx.Request.Header[http.CanonicalHeaderKey("User-ID")]
if len(userId) == 0 {
ctx.String(http.StatusForbidden, "Fuck you!")
return
}
if !database.MatchTokenUid(authToken, userId[0]) {
ctx.String(http.StatusForbidden, "Fuck you!")
return
}
nonce, err := utils.GetAuthorizeNonce(authorizeStr)
if err != nil {
fmt.Println(err)
ctx.String(http.StatusForbidden, "Fuck you!")
return
}
nonce++
respTime := time.Now().Unix()
newAuthorizeStr := fmt.Sprintf("consumerKey=lovelive_test&timeStamp=%d&version=1.1&token=%s&nonce=%d&user_id=%s&requestTimeStamp=%d", respTime, authToken, nonce, userId[0], reqTime)
// fmt.Println(newAuthorizeStr)
downloadReq := model.BatchReq{}
if err := json.Unmarshal([]byte(ctx.PostForm("request_data")), &downloadReq); err != nil {
panic(err)
}
pkgList := []model.BatchResult{}
if downloadReq.ClientVersion == PackageVersion && CdnUrl != "" {
pkgType := downloadReq.PackageType
stmt, err := db.Prepare("SELECT pkg_id,pkg_order,pkg_size FROM download_db WHERE pkg_type = ? ORDER BY pkg_id ASC, pkg_order ASC")
if err != nil {
panic(err)
}
rows, err := stmt.Query(pkgType)
if err != nil {
panic(err)
}
for rows.Next() {
var pkgId, pkgOrder, pkgSize int
err = rows.Scan(&pkgId, &pkgOrder, &pkgSize)
if err != nil {
panic(err)
}
pkgList = append(pkgList, model.BatchResult{
Size: pkgSize,
URL: fmt.Sprintf("%s/%d_%d_%d.zip", CdnUrl, pkgType, pkgId, pkgOrder),
})
}
}
batchResp := model.BatchResp{
ResponseData: pkgList,
ReleaseInfo: []interface{}{},
StatusCode: 200,
}
@@ -60,6 +176,89 @@ func DownloadBatchHandler(ctx *gin.Context) {
if err != nil {
panic(err)
}
// fmt.Println(string(resp))
xms := encrypt.RSA_Sign_SHA1(resp, "privatekey.pem")
xms64 := base64.RawStdEncoding.EncodeToString(xms)
ctx.Header("user_id", userId[0])
ctx.Header("authorize", newAuthorizeStr)
ctx.Header("X-Message-Sign", xms64)
ctx.String(http.StatusOK, string(resp))
}
func DownloadUpdateHandler(ctx *gin.Context) {
db, err := sql.Open("sqlite3", "assets/main.db")
if err != nil {
panic(err)
}
defer db.Close()
reqTime := time.Now().Unix()
authorizeStr := ctx.Request.Header["Authorize"]
authToken, err := utils.GetAuthorizeToken(authorizeStr)
if err != nil {
ctx.String(http.StatusForbidden, "Fuck you!")
return
}
userId := ctx.Request.Header[http.CanonicalHeaderKey("User-ID")]
if len(userId) == 0 {
ctx.String(http.StatusForbidden, "Fuck you!")
return
}
if !database.MatchTokenUid(authToken, userId[0]) {
ctx.String(http.StatusForbidden, "Fuck you!")
return
}
nonce, err := utils.GetAuthorizeNonce(authorizeStr)
if err != nil {
fmt.Println(err)
ctx.String(http.StatusForbidden, "Fuck you!")
return
}
nonce++
respTime := time.Now().Unix()
newAuthorizeStr := fmt.Sprintf("consumerKey=lovelive_test&timeStamp=%d&version=1.1&token=%s&nonce=%d&user_id=%s&requestTimeStamp=%d", respTime, authToken, nonce, userId[0], reqTime)
// fmt.Println(newAuthorizeStr)
downloadReq := model.UpdateReq{}
if err := json.Unmarshal([]byte(ctx.PostForm("request_data")), &downloadReq); err != nil {
panic(err)
}
pkgList := []model.UpdateResult{}
if downloadReq.ExternalVersion != PackageVersion && CdnUrl != "" {
pkgType := 99
rows, err := db.Query("SELECT pkg_id,pkg_order,pkg_size FROM download_db WHERE pkg_type = 99 ORDER BY pkg_id ASC, pkg_order ASC")
if err != nil {
panic(err)
}
for rows.Next() {
var pkgId, pkgOrder, pkgSize int
err = rows.Scan(&pkgId, &pkgOrder, &pkgSize)
if err != nil {
panic(err)
}
pkgList = append(pkgList, model.UpdateResult{
Size: pkgSize,
URL: fmt.Sprintf("%s/%d_%d_%d.zip", CdnUrl, pkgType, pkgId, pkgOrder),
Version: PackageVersion,
})
}
}
updateResp := model.UpdateResp{
ResponseData: pkgList,
ReleaseInfo: []interface{}{},
StatusCode: 200,
}
resp, err := json.Marshal(updateResp)
if err != nil {
panic(err)
}
// fmt.Println(string(resp))
xms := encrypt.RSA_Sign_SHA1(resp, "privatekey.pem")
xms64 := base64.RawStdEncoding.EncodeToString(xms)
@@ -101,7 +300,7 @@ func DownloadEventHandler(ctx *gin.Context) {
newAuthorizeStr := fmt.Sprintf("consumerKey=lovelive_test&timeStamp=%d&version=1.1&token=%s&nonce=%d&user_id=%s&requestTimeStamp=%d", respTime, authToken, nonce, userId[0], reqTime)
// fmt.Println(newAuthorizeStr)
eventResp := DownloadResp{
eventResp := model.EventResp{
ResponseData: []interface{}{},
ReleaseInfo: []interface{}{},
StatusCode: 200,
+11 -1
View File
@@ -1,5 +1,15 @@
package handler
import "honoka-chan/config"
var (
nonce = 0
nonce = 0
PackageVersion = "97.4.6"
CdnUrl string
)
func init() {
if config.Conf.Cdn.CdnUrl != "" {
CdnUrl = config.Conf.Cdn.CdnUrl
}
}
+98
View File
@@ -0,0 +1,98 @@
package handler
import (
"encoding/base64"
"encoding/json"
"fmt"
"honoka-chan/config"
"honoka-chan/database"
"honoka-chan/encrypt"
"honoka-chan/utils"
"net/http"
"time"
"github.com/gin-gonic/gin"
)
type MultiUnitStartUpResp struct {
ResponseData MultiUnitStartUpData `json:"response_data"`
ReleaseInfo []interface{} `json:"release_info"`
StatusCode int `json:"status_code"`
}
type MultiUnitStartUpData struct {
MultiUnitScenarioID int `json:"multi_unit_scenario_id"`
ScenarioAdjustment int `json:"scenario_adjustment"`
ServerTimestamp int64 `json:"server_timestamp"`
}
type MultiUnitStartUpReq struct {
Module string `json:"module"`
Action string `json:"action"`
TimeStamp int `json:"timeStamp"`
Mgd int `json:"mgd"`
MultiUnitScenarioID int `json:"multi_unit_scenario_id"`
CommandNum string `json:"commandNum"`
}
func MultiUnitStartUpHandler(ctx *gin.Context) {
reqTime := time.Now().Unix()
startReq := MultiUnitStartUpReq{}
err := json.Unmarshal([]byte(ctx.PostForm("request_data")), &startReq)
if err != nil {
panic(err)
}
authorizeStr := ctx.Request.Header["Authorize"]
authToken, err := utils.GetAuthorizeToken(authorizeStr)
if err != nil {
ctx.String(http.StatusForbidden, "Fuck you!")
return
}
userId := ctx.Request.Header[http.CanonicalHeaderKey("User-ID")]
if len(userId) == 0 {
ctx.String(http.StatusForbidden, "Fuck you!")
return
}
if !database.MatchTokenUid(authToken, userId[0]) {
ctx.String(http.StatusForbidden, "Fuck you!")
return
}
nonce, err := utils.GetAuthorizeNonce(authorizeStr)
if err != nil {
fmt.Println(err)
ctx.String(http.StatusForbidden, "Fuck you!")
return
}
nonce++
respTime := time.Now().Unix()
newAuthorizeStr := fmt.Sprintf("consumerKey=lovelive_test&timeStamp=%d&version=1.1&token=%s&nonce=%d&user_id=%s&requestTimeStamp=%d", respTime, authToken, nonce, userId[0], reqTime)
// fmt.Println(newAuthorizeStr)
startResp := MultiUnitStartUpResp{
ResponseData: MultiUnitStartUpData{
MultiUnitScenarioID: startReq.MultiUnitScenarioID,
ScenarioAdjustment: 50,
ServerTimestamp: time.Now().Unix(),
},
ReleaseInfo: []interface{}{},
StatusCode: 200,
}
resp, err := json.Marshal(startResp)
if err != nil {
panic(err)
}
xms := encrypt.RSA_Sign_SHA1(resp, "privatekey.pem")
xms64 := base64.RawStdEncoding.EncodeToString(xms)
ctx.Header("Server-Version", config.Conf.Server.VersionNumber)
ctx.Header("user_id", userId[0])
ctx.Header("authorize", newAuthorizeStr)
ctx.Header("X-Message-Sign", xms64)
ctx.String(http.StatusOK, string(resp))
}
+3
View File
@@ -54,7 +54,9 @@ func main() {
m.POST("/gdpr/get", handler.GdprHandler)
m.POST("/personalnotice/get", handler.PersonalNoticeHandler)
m.POST("/tos/tosCheck", handler.TosCheckHandler)
m.POST("/download/additional", handler.DownloadAdditionalHandler)
m.POST("/download/batch", handler.DownloadBatchHandler)
m.POST("/download/update", handler.DownloadUpdateHandler)
m.POST("/download/event", handler.DownloadEventHandler)
m.POST("/lbonus/execute", handler.LBonusExecuteHandler)
m.POST("/api", handler.ApiHandler)
@@ -78,6 +80,7 @@ func main() {
m.POST("/notice/noticeFriendVariety", handler.NoticeFriendVarietyHandler)
m.POST("/notice/noticeFriendGreeting", handler.NoticeFriendGreetingHandler)
m.POST("/notice/noticeUserGreetingHistory", handler.NoticeUserGreetingHandler)
m.POST("/multiunit/scenarioStartup", handler.MultiUnitStartUpHandler)
}
r.GET("/webview.php/announce/index", handler.AnnounceIndexHandler)
// Server APIs
+71
View File
@@ -0,0 +1,71 @@
package model
type AdditionalReq struct {
Module string `json:"module"`
Mgd int `json:"mgd"`
Action string `json:"action"`
TimeStamp int `json:"timeStamp"`
PackageID int `json:"package_id"`
TargetOs string `json:"target_os"`
PackageType int `json:"package_type"`
CommandNum string `json:"commandNum"`
}
type AdditionalResult struct {
Size int `json:"size"`
URL string `json:"url"`
}
type AdditionalResp struct {
ResponseData []AdditionalResult `json:"response_data"`
ReleaseInfo []interface{} `json:"release_info"`
StatusCode int `json:"status_code"`
}
type BatchReq struct {
ClientVersion string `json:"client_version"`
Os string `json:"os"`
PackageType int `json:"package_type"`
ExcludedPackageIds []interface{} `json:"excluded_package_ids"`
CommandNum string `json:"commandNum"`
}
type BatchResult struct {
Size int `json:"size"`
URL string `json:"url"`
}
type BatchResp struct {
ResponseData []BatchResult `json:"response_data"`
ReleaseInfo []interface{} `json:"release_info"`
StatusCode int `json:"status_code"`
}
type UpdateReq struct {
Module string `json:"module"`
TargetOs string `json:"target_os"`
InstallVersion string `json:"install_version"`
TimeStamp int `json:"timeStamp"`
Action string `json:"action"`
PackageList []interface{} `json:"package_list"`
CommandNum string `json:"commandNum"`
ExternalVersion string `json:"external_version"`
}
type UpdateResult struct {
Size int `json:"size"`
URL string `json:"url"`
Version string `json:"version"`
}
type UpdateResp struct {
ResponseData []UpdateResult `json:"response_data"`
ReleaseInfo []interface{} `json:"release_info"`
StatusCode int `json:"status_code"`
}
type EventResp struct {
ResponseData []interface{} `json:"response_data"`
ReleaseInfo []interface{} `json:"release_info"`
StatusCode int `json:"status_code"`
}
+62
View File
@@ -0,0 +1,62 @@
package tools
import (
"database/sql"
"fmt"
"os"
"strings"
_ "github.com/mattn/go-sqlite3"
)
func GenDownloadDb() {
// Create table
// sql := `CREATE TABLE "main"."download_db" (
// "id" integer NOT NULL,
// "pkg_type" integer,
// "pkg_id" integer,
// "pkg_order" integer,
// "pkg_size" integer,
// PRIMARY KEY ("id")
// )`
db, err := sql.Open("sqlite3", "assets/main.db")
if err != nil {
panic(err)
}
defer db.Close()
fileLists, err := os.ReadDir("F:/sif_dl/list_CN_Android")
if err != nil {
panic(err)
}
for _, v := range fileLists {
if v.IsDir() {
panic(err)
}
fileList := "F:/sif_dl/list_CN_Android/" + v.Name()
fileStat, err := os.Stat(fileList)
if err != nil {
panic(err)
}
pkgSize := fileStat.Size()
fileInfo := strings.Split(strings.ReplaceAll(v.Name(), ".zip", ""), "_")
pkgType, pkgId, pkgOrder := fileInfo[0], fileInfo[1], fileInfo[2]
fmt.Printf("%s - %s - %s - %d\n", pkgType, pkgId, pkgOrder, pkgSize)
stmt, err := db.Prepare("INSERT INTO download_db(pkg_type,pkg_id,pkg_order,pkg_size) VALUES (?,?,?,?)")
if err != nil {
panic(err)
}
res, err := stmt.Exec(pkgType, pkgId, pkgOrder, pkgSize)
if err != nil {
panic(err)
}
id, err := res.LastInsertId()
if err != nil {
panic(err)
}
fmt.Println("LastInsertId:", id)
}
}
+1
View File
@@ -9,4 +9,5 @@ func init() {
LoadApi3Data("assets/api3.json")
// ListUnitData()
// go SyncNotesList()
// GenDownloadDb()
}