Commit 6a9e6011 authored by 贾浩@五瓣科技's avatar 贾浩@五瓣科技

dry

parents
.idea
*.iml
out
gen
*.sol
*.txt
.DS_Store
*.exe
build
log
\ No newline at end of file
FROM golang:1.21-alpine AS base
# Set up dependencies
ENV PACKAGES git openssh-client build-base
# Install dependencies
RUN apk add --update $PACKAGES
# Add source files
RUN mkdir -p ./sdk-api
COPY ./ ./sdk-api/
FROM base AS build
RUN cd sdk-api && go mod tidy && go build -v -o /tmp/api ./cmd/api && go build -v -o /tmp/messenger ./cmd/messenger
FROM alpine
WORKDIR /app
COPY ./config.toml /config.toml
COPY --from=build /tmp/api /usr/bin/api
COPY --from=build /tmp/messenger /usr/bin/messenger
EXPOSE 8080
\ No newline at end of file
.PHONY: default all clean dev messenger
GOBIN = $(shell pwd)/build/bin
default: all
all: api
api:
go build $(BUILD_FLAGS) -v -o=${GOBIN}/$@ ./cmd/api
messenger:
go build $(BUILD_FLAGS) -v -o=${GOBIN}/$@ ./cmd/messenger
docker:
docker build -t caduceus/tg-messenger:latest -f Dockerfile .
package main
import (
"flag"
"io"
"os"
"sdk_api/config"
"sdk_api/dao"
"sdk_api/server"
"sdk_api/service"
log "github.com/sirupsen/logrus"
)
func initLog() {
file, _ := os.OpenFile("log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
mw := io.MultiWriter(os.Stdout, file)
log.SetOutput(mw)
log.SetFormatter(&log.TextFormatter{
FullTimestamp: true,
})
}
func main() {
initLog()
flag.Parse()
cfg, err := config.New()
if err != nil {
panic(err)
}
da, err := dao.New(cfg)
if err != nil {
panic(err)
}
if cfg.Debug {
log.SetLevel(log.DebugLevel)
}
svs := service.New(cfg, da)
server.StartServer(svs, cfg)
}
debug = true
[mysql]
host = "127.0.0.1"
port = 3306
user = "root"
password = ""
database = "task"
max_conn = 10
max_idle_conn = 2
enable_log = true
[server]
listen = "0.0.0.0:8080"
[tg_bot]
token = "6507972032:AAFAjaNz70ibA42kSH7k2gblyIQa1gWJiW0"
package config
import (
"flag"
"github.com/BurntSushi/toml"
)
type Config struct {
Debug bool `toml:"debug"`
MySQL MysqlConfig `toml:"mysql"`
Server ServerConfig `toml:"server"`
TGBot TGBotConfig `toml:"tg_bot"`
Supabase SupabaseConfig `toml:"supabase"`
}
type SupabaseConfig struct {
APIKey string `toml:"api_key"`
Email string `toml:"email"`
Password string `toml:"password"`
}
type MysqlConfig struct {
Host string `toml:"host"`
Port int `toml:"port"`
User string `toml:"user"`
Password string `toml:"password"`
Database string `toml:"database"`
MaxConn int `toml:"max_conn"`
MaxIdleConn int `toml:"max_idle_conn"`
EnableLog bool `toml:"enable_log"`
}
type ServerConfig struct {
Listen string `toml:"listen"`
}
type TGBotConfig struct {
Token string `toml:"token"`
}
var confPath = flag.String("c", "config.toml", "config file path")
func New() (config *Config, err error) {
config = new(Config)
_, err = toml.DecodeFile(*confPath, config)
return
}
package constant
import (
"math/big"
)
const JwtSecret = "VrA1tFnHBhNTPRriHdUQLuFHb4PAFPAa"
const (
InvalidParam = "invalid param"
InternalError = "internal error"
)
var (
ZeroValue = big.NewInt(0)
Gwei = big.NewInt(1000000000)
Ether = big.NewInt(1000000000000000000)
)
const (
TaskPlatformApp = "app"
TaskPlatformTwitter = "twitter"
TaskPlatformTelegram = "telegram"
)
var validPlatforms = map[string]bool{
TaskPlatformApp: true,
TaskPlatformTwitter: true,
TaskPlatformTelegram: true,
}
func IsValidPlatform(platform string) bool {
_, ok := validPlatforms[platform]
return ok
}
const (
TaskActionJoin = "join"
TaskActionActive = "active"
TaskActionFollow = "follow"
TaskActionLike = "like"
TaskActionReply = "reply"
TaskActionRetweet = "retweet"
TaskActionInvite = "invite"
)
var validActions = map[string]bool{
TaskActionJoin: true,
TaskActionActive: true,
TaskActionFollow: true,
TaskActionLike: true,
TaskActionReply: true,
TaskActionRetweet: true,
TaskActionInvite: true,
}
func IsValidAction(action string) bool {
_, ok := validActions[action]
return ok
}
package dao
import (
"sdk_api/config"
"github.com/supabase-community/supabase-go"
"gorm.io/gorm"
)
type Dao struct {
c *config.Config
db *gorm.DB
supa *supabase.Client
}
func New(_c *config.Config) (dao *Dao, err error) {
dao = &Dao{
c: _c,
}
// dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True",
// _c.MySQL.User, _c.MySQL.Password, _c.MySQL.Host, _c.MySQL.Port, _c.MySQL.Database)
// dsn := fmt.Sprintf("host=%s user=%s password=%s dbname=postgres port=5432 sslmode=disable search_path=taskcenter",
// "43.198.54.207", "postgres", "wuban-password",
// )
// fmt.Println(dsn)
//
// lgr := logger.Default
// if _c.MySQL.EnableLog {
// lgr = logger.Default.LogMode(logger.Info)
// }
//
// dao.db, err = gorm.Open(postgres.Open(dsn), &gorm.Config{
// NamingStrategy: schema.NamingStrategy{
// SingularTable: true,
// },
// DisableForeignKeyConstraintWhenMigrating: true, // 停用外键约束
// Logger: lgr,
// })
// if err != nil {
// return
// }
// sqlDB, err := dao.db.DB()
// if err != nil {
// return
// }
// sqlDB.SetMaxOpenConns(_c.MySQL.MaxConn)
// sqlDB.SetMaxIdleConns(_c.MySQL.MaxIdleConn)
// sqlDB.SetConnMaxIdleTime(time.Hour)
// err = dao.db.AutoMigrate(&dbModel.Project{}, &dbModel.TaskGroup{}, &dbModel.Task{}, &dbModel.TaskHistory{})
// if err != nil {
// return
// }
return dao, nil
}
package dao
import (
dbModel "sdk_api/model/db"
"gorm.io/gorm"
)
func (d *Dao) CreateProject(p *dbModel.Project) (err error) {
return d.db.Create(p).Error
}
func (d *Dao) GetProjectList(page, pageSize int) (list []*dbModel.Project, err error) {
return list, d.db.Limit(pageSize).Offset((page - 1) * pageSize).Find(&list).Error
}
func (d *Dao) GetProject(id int) (p *dbModel.Project, err error) {
p = &dbModel.Project{}
err = d.db.Where("`id` = ?", id).First(&p).Error
if err == gorm.ErrRecordNotFound {
return nil, nil
}
return p, err
}
func (d *Dao) CreateGroup(g *dbModel.TaskGroup) (err error) {
return d.db.Create(g).Error
}
func (d *Dao) GetGroupList(page, pageSize int) (list []*dbModel.TaskGroup, err error) {
return list, d.db.Limit(pageSize).Offset((page - 1) * pageSize).Find(&list).Error
}
func (d *Dao) GetGroup(id int) (g *dbModel.TaskGroup, err error) {
g = &dbModel.TaskGroup{}
err = d.db.Where("`id` = ?", id).First(&g).Error
if err == gorm.ErrRecordNotFound {
return nil, nil
}
return g, err
}
func (d *Dao) GetGroupTasks(gid int) (list []*dbModel.Task, err error) {
return list, d.db.Where("`group_id` = ?", gid).Find(&list).Error
}
func (d *Dao) CreateGroupTask(gt *dbModel.Task) (err error) {
return d.db.Create(gt).Error
}
package dao
import (
"testing"
)
func TestMigrate(t *testing.T) {
}
networks:
default:
name: aon-backend
services:
tg-messenger-api:
image: caduceus/tg-messenger:latest
pull_policy: always
container_name: tg-messenger-api
ports:
- "16669:8080"
depends_on:
aon-db:
condition: service_healthy
volumes:
- ./conf/tg-messenger/config.toml:/config.toml
- ./data/tg-messenger/api-log:/app
command:
- "/bin/sh"
- "-c"
- "/usr/bin/api -c /config.toml"
restart:
unless-stopped
tg-messenger:
image: caduceus/tg-messenger:latest
pull_policy: always
container_name: tg-messenger
depends_on:
aon-db:
condition: service_healthy
volumes:
- ./conf/tg-messenger/config.toml:/config.toml
- ./data/tg-messenger/messenger-log:/app
command:
- "/bin/sh"
- "-c"
- "/usr/bin/messenger -c /config.toml"
restart:
unless-stopped
\ No newline at end of file
module sdk_api
go 1.21.4
require (
github.com/BurntSushi/toml v0.3.1
github.com/bwmarrin/snowflake v0.3.0
github.com/gin-contrib/cors v1.7.2
github.com/gin-gonic/gin v1.10.0
github.com/golang-jwt/jwt/v5 v5.2.1
github.com/sirupsen/logrus v1.9.0
github.com/supabase-community/supabase-go v0.0.4
github.com/tidwall/gjson v1.17.1
gorm.io/driver/postgres v1.5.9
gorm.io/gorm v1.25.10
)
require (
github.com/bytedance/sonic v1.11.6 // indirect
github.com/bytedance/sonic/loader v0.1.1 // indirect
github.com/cloudwego/base64x v0.1.4 // indirect
github.com/cloudwego/iasm v0.2.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.20.0 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
github.com/jackc/pgx/v5 v5.5.5 // indirect
github.com/jackc/puddle/v2 v2.2.1 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/supabase-community/functions-go v0.0.0-20220927045802-22373e6cb51d // indirect
github.com/supabase-community/gotrue-go v1.2.0 // indirect
github.com/supabase-community/postgrest-go v0.0.11 // indirect
github.com/supabase-community/storage-go v0.7.0 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.0 // indirect
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect
golang.org/x/arch v0.8.0 // indirect
golang.org/x/crypto v0.23.0 // indirect
golang.org/x/net v0.25.0 // indirect
golang.org/x/sync v0.1.0 // indirect
golang.org/x/sys v0.20.0 // indirect
golang.org/x/text v0.15.0 // indirect
google.golang.org/protobuf v1.34.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/bwmarrin/snowflake v0.3.0 h1:xm67bEhkKh6ij1790JB83OujPR5CzNe8QuQqAgISZN0=
github.com/bwmarrin/snowflake v0.3.0/go.mod h1:NdZxfVWX+oR6y2K0o6qAYv6gIOP9rjG0/E9WsDpxqwE=
github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0=
github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
github.com/gin-contrib/cors v1.7.2 h1:oLDHxdg8W/XDoN/8zamqk/Drgt4oVZDvaV0YmvVICQw=
github.com/gin-contrib/cors v1.7.2/go.mod h1:SUJVARKgQ40dmrzgXEVxj2m7Ig1v1qIboQkPDTQ9t2E=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8=
github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgx/v5 v5.5.5 h1:amBjrZVmksIdNjxGW/IiIMzxMKZFelXbUoPNb+8sjQw=
github.com/jackc/pgx/v5 v5.5.5/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A=
github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/jarcoal/httpmock v1.3.1 h1:iUx3whfZWVf3jT01hQTO/Eo5sAYtB2/rqaUuOtpInww=
github.com/jarcoal/httpmock v1.3.1/go.mod h1:3yb8rc4BI7TCBhFY8ng0gjuLKJNquuDNiPaZjnENuYg=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/supabase-community/functions-go v0.0.0-20220927045802-22373e6cb51d h1:LOrsumaZy615ai37h9RjUIygpSubX+F+6rDct1LIag0=
github.com/supabase-community/functions-go v0.0.0-20220927045802-22373e6cb51d/go.mod h1:nnIju6x3+OZSojtGQCQzu0h3kv4HdIZk+UWCnNxtSak=
github.com/supabase-community/gotrue-go v1.2.0 h1:Zm7T5q3qbuwPgC6xyomOBKrSb7X5dvmjDZEmNST7MoE=
github.com/supabase-community/gotrue-go v1.2.0/go.mod h1:86DXBiAUNcbCfgbeOPEh0PQxScLfowUbYgakETSFQOw=
github.com/supabase-community/postgrest-go v0.0.11 h1:717GTUMfLJxSBuAeEQG2MuW5Q62Id+YrDjvjprTSErg=
github.com/supabase-community/postgrest-go v0.0.11/go.mod h1:cw6LfzMyK42AOSBA1bQ/HZ381trIJyuui2GWhraW7Cc=
github.com/supabase-community/storage-go v0.7.0 h1:cJ8HLbbnL54H5rHPtHfiwtpRwcbDfA3in9HL/ucHnqA=
github.com/supabase-community/storage-go v0.7.0/go.mod h1:oBKcJf5rcUXy3Uj9eS5wR6mvpwbmvkjOtAA+4tGcdvQ=
github.com/supabase-community/supabase-go v0.0.4 h1:sxMenbq6N8a3z9ihNpN3lC2FL3E1YuTQsjX09VPRp+U=
github.com/supabase-community/supabase-go v0.0.4/go.mod h1:SSHsXoOlc+sq8XeXaf0D3gE2pwrq5bcUfzm0+08u/o8=
github.com/tidwall/gjson v1.17.1 h1:wlYEnwqAHgzmhNUFfw7Xalt2JzQvsMx2Se4PcoFCT/U=
github.com/tidwall/gjson v1.17.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 h1:nrZ3ySNYwJbSpD6ce9duiP+QkD3JuLCcWkdaehUS/3Y=
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80/go.mod h1:iFyPdL66DjUD96XmzVL3ZntbzcflLnznH0fr99w5VqE=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc=
golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/postgres v1.5.9 h1:DkegyItji119OlcaLjqN11kHoUgZ/j13E0jkJZgD6A8=
gorm.io/driver/postgres v1.5.9/go.mod h1:DX3GReXH+3FPWGrrgffdvCk3DQ1dwDPdmbenSkweRGI=
gorm.io/gorm v1.25.10 h1:dQpO+33KalOA+aFYGlK+EfxcI5MbO7EP2yYygwh9h+s=
gorm.io/gorm v1.25.10/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
package middleware
import (
"bytes"
"io"
"github.com/gin-gonic/gin"
log "github.com/sirupsen/logrus"
)
func PrintRequestResponseBodyMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
// 读取请求 body
var requestBody []byte
if c.Request.Body != nil {
requestBody, _ = io.ReadAll(c.Request.Body)
c.Request.Body = io.NopCloser(bytes.NewBuffer(requestBody))
}
log.WithFields(log.Fields{"method": c.Request.Method, "uri": c.Request.RequestURI, "body": string(requestBody)}).Debug("request body")
bodyWriter := &responseBodyWriter{body: bytes.NewBufferString(""), ResponseWriter: c.Writer}
c.Writer = bodyWriter
c.Next()
responseBody := bodyWriter.body.String()
log.WithFields(log.Fields{"status": c.Writer.Status(), "body": responseBody}).Debug("response body")
}
}
type responseBodyWriter struct {
gin.ResponseWriter
body *bytes.Buffer
}
func (r *responseBodyWriter) Write(b []byte) (int, error) {
r.body.Write(b)
return r.ResponseWriter.Write(b)
}
package middleware
import (
"sdk_api/util"
"github.com/gin-gonic/gin"
log "github.com/sirupsen/logrus"
)
func JWTMiddleware(c *gin.Context) {
tokenString := c.GetHeader("Authorization")
log.Debugln(tokenString)
if tokenString == "" || len(tokenString) < 7 {
c.JSON(200, gin.H{
"code": 1,
"msg": "invalid token",
"data": "",
})
c.Abort()
return
}
ok, expired, uid, _, _ := util.ParseJWT(tokenString[7:])
if !ok {
c.JSON(200, gin.H{
"code": 1,
"msg": "invalid token",
"data": "",
})
c.Abort()
return
}
if expired {
c.JSON(200, gin.H{
"code": 1,
"msg": "token expired",
"data": "",
})
c.Abort()
return
}
log.WithField("uid", uid).Debug("jwt uid")
c.Set("jwt-uid", uid)
c.Next()
}
package api_model
type CreateProjectRequest struct {
ProjectName string `json:"projectName" binding:"required"`
TelegramChatId int `json:"telegramChatId" binding:"required"`
TwitterHandle string `json:"twitterHandle" binding:"required"`
}
type GetProjectResponse struct {
ProjectName string `json:"projectName"`
TelegramChatId int `json:"telegramChatId"`
TwitterHandle string `json:"twitterHandle"`
}
type CreateGroupRequest struct {
ProjectId int `json:"projectId" binding:"required"`
Description string `json:"description"`
Tasks []Task `json:"tasks"`
}
type Task struct {
TaskId int `json:"taskId,omitempty"`
Platform string `json:"platform" binding:"required"`
Action string `json:"action" binding:"required"`
Url string `json:"url" binding:"required"`
Description string `json:"description" binding:"required"`
Reward int `json:"reward" binding:"required"`
Start int `json:"start" binding:"required"`
End int `json:"end" binding:"required"`
}
type GetGroupResponse CreateGroupRequest
package db_model
import (
"gorm.io/gorm"
)
type Project struct {
Id int `gorm:"primaryKey;autoIncrement:false"`
Name string `gorm:"type:text;not null;comment:项目名称"`
TelegramChatId int `gorm:"type:int;not null;comment:telegram群id"`
TwitterHandle string `gorm:"type:text;not null;comment:twitter用户名"`
gorm.Model
Groups []*TaskGroup
}
type TaskGroup struct {
Id int `gorm:"primaryKey;autoIncrement:false"`
ProjectId int `gorm:"type:int;not null;comment:项目id"`
Description string `gorm:"type:text;not null;comment:任务组描述"`
gorm.Model
}
type Task struct {
Id int `gorm:"primaryKey;autoIncrement:false"`
GroupId int `gorm:"type:int;index;not null;comment:任务组id"`
Platform string `gorm:"type:text;not null;comment:任务平台"`
Action string `gorm:"type:text;not null;comment:任务动作"`
Url string `gorm:"type:text;not null;comment:任务地址"`
Description string `gorm:"type:text;not null;comment:任务描述"`
Reward int `gorm:"type:int;not null;comment:任务奖励"`
Start int `gorm:"type:int;not null;comment:任务开始时间"`
End int `gorm:"type:int;not null;comment:任务结束时间"`
gorm.Model
}
type TaskHistory struct {
Id int `gorm:"primaryKey"`
TaskId int `gorm:"type:int;index;not null;comment:任务id"`
User string `gorm:"type:text;not null;comment:用户"`
gorm.Model
}
# telegram-任务中心
和sdk部分共用一个数据库,启动&停止命令
```
docker compose -f docker-compose-ai-sdk-api.yml -f docker-compose-tg-messenger.yml up -d tg-messenger tg-messenger-api
docker compose -f docker-compose-ai-sdk-api.yml -f docker-compose-tg-messenger.yml down tg-messenger tg-messenger-api
```
\ No newline at end of file
package server
import (
"sdk_api/constant"
apiModel "sdk_api/model/api"
"strconv"
"github.com/gin-gonic/gin"
)
func createGroup(c *gin.Context) {
req := &apiModel.CreateGroupRequest{}
if err := c.ShouldBindJSON(req); err != nil {
c.JSON(200, withError(constant.InvalidParam))
return
}
if len(req.Tasks) == 0 {
c.JSON(200, withError(constant.InvalidParam))
return
}
project, err := srv.GetProject(req.ProjectId)
if err != nil {
c.JSON(200, withError(constant.InternalError))
return
}
if project == nil {
c.JSON(200, withError("project not found"))
return
}
for _, task := range req.Tasks {
if !constant.IsValidAction(task.Action) || !constant.IsValidPlatform(task.Platform) {
c.JSON(200, withError(constant.InvalidParam))
return
}
}
gid, err := srv.CreateGroup(req)
if err != nil {
c.JSON(200, withError(constant.InternalError))
return
}
c.JSON(200, withSuccess(gin.H{"groupId": gid}))
}
func getGroup(c *gin.Context) {
_gid := c.Param("gid")
gid, _ := strconv.Atoi(_gid)
if gid == 0 {
c.JSON(200, withError(constant.InvalidParam))
return
}
resp, err := srv.GetGroup(gid)
if err != nil {
c.JSON(200, withError(constant.InternalError))
return
}
c.JSON(200, withSuccess(resp))
}
func checkTask(c *gin.Context) {
}
package server
import (
"sdk_api/constant"
apiModel "sdk_api/model/api"
"strconv"
"github.com/gin-gonic/gin"
)
func createProject(c *gin.Context) {
req := &apiModel.CreateProjectRequest{}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(200, withError(constant.InvalidParam))
return
}
pid, err := srv.CreateProject(req)
if err != nil {
c.JSON(200, withError(constant.InternalError))
return
}
c.JSON(200, withSuccess(gin.H{"projectId": pid}))
}
func listProject(c *gin.Context) {
_page := c.DefaultQuery("page", "1")
_pageSize := c.DefaultQuery("pageSize", "10")
page, _ := strconv.Atoi(_page)
pageSize, _ := strconv.Atoi(_pageSize)
if page < 1 || pageSize < 1 || pageSize > 100 {
c.JSON(200, withError(constant.InvalidParam))
return
}
resp, err := srv.GetProjectList(page, pageSize)
if err != nil {
c.JSON(200, withError(constant.InternalError))
return
}
c.JSON(200, withSuccess(resp))
}
func getProject(c *gin.Context) {
_pid := c.Param("pid")
pid, _ := strconv.Atoi(_pid)
if pid == 0 {
c.JSON(200, withError(constant.InvalidParam))
return
}
resp, err := srv.GetProject(pid)
if err != nil {
c.JSON(200, withError(constant.InternalError))
return
}
c.JSON(200, withSuccess(resp))
}
package server
import (
"sdk_api/middleware"
"github.com/gin-gonic/gin"
)
func initRouter(e *gin.Engine) {
e.Use(middleware.PrintRequestResponseBodyMiddleware())
v1 := e.Group("/api/v1")
{
project := v1.Group("/project")
project.GET("/:pid", getProject) // 获取项目详情
project.GET("/list", listProject) // 获取项目列表
project.POST("/create", createProject) // 创建项目
}
{
group := v1.Group("/group")
group.GET("/:gid", getGroup) // 获取任务组任务详情
group.GET("/:gid/:tid/check", checkTask) // 检查任务是否完成
group.POST("/create", createGroup) // 创建任务组
}
}
package server
import (
"sdk_api/config"
"sdk_api/service"
"github.com/gin-contrib/cors"
"github.com/gin-gonic/gin"
log "github.com/sirupsen/logrus"
)
var srv *service.Service
var conf *config.Config
func StartServer(_srv *service.Service, _conf *config.Config) {
srv = _srv
conf = _conf
if !conf.Debug {
gin.SetMode(gin.ReleaseMode)
}
engine := gin.Default()
_cors := cors.DefaultConfig()
_cors.AllowAllOrigins = true
_cors.AllowHeaders = []string{"*"}
engine.Use(cors.New(_cors))
initRouter(engine)
log.Infof("start http server listening %s", conf.Server.Listen)
if err := engine.Run(conf.Server.Listen); err != nil {
log.Error("http server run error: ", err)
}
}
func withSuccess(obj interface{}) interface{} {
return gin.H{
"code": 0,
"msg": "ok",
"data": obj,
}
}
func withError(msg string) interface{} {
return gin.H{
"code": 1,
"error": msg,
"data": "",
}
}
package service
import (
apiModel "sdk_api/model/api"
dbModel "sdk_api/model/db"
"sdk_api/util"
log "github.com/sirupsen/logrus"
)
func (s *Service) CreateGroup(req *apiModel.CreateGroupRequest) (gid int, err error) {
g := &dbModel.TaskGroup{
Id: util.GenFlakeID(),
ProjectId: req.ProjectId,
Description: req.Description,
}
err = s.d.CreateGroup(g)
if err != nil {
log.WithError(err).Error("create group error")
return
}
for _, task := range req.Tasks {
gt := &dbModel.Task{
Id: util.GenFlakeID(),
GroupId: g.Id,
Platform: task.Platform,
Action: task.Action,
Url: task.Url,
Description: task.Description,
Reward: task.Reward,
Start: task.Start,
End: task.End,
}
err = s.d.CreateGroupTask(gt)
if err != nil {
log.WithError(err).Error("create group task error")
return 0, err
}
}
return g.Id, nil
}
func (s *Service) GetGroup(gid int) (resp *apiModel.GetGroupResponse, err error) {
resp = &apiModel.GetGroupResponse{Tasks: make([]apiModel.Task, 0)}
g, err := s.d.GetGroup(gid)
if err != nil {
log.WithError(err).Error("get group error")
return
}
if g == nil {
log.WithError(err).Error("group not found")
return nil, nil
}
tasks, err := s.d.GetGroupTasks(g.Id)
if err != nil {
log.WithError(err).Error("get group tasks error")
return
}
for _, task := range tasks {
resp.Tasks = append(resp.Tasks, apiModel.Task{
TaskId: task.Id,
Platform: task.Platform,
Action: task.Action,
Url: task.Url,
Description: task.Description,
Reward: task.Reward,
Start: task.Start,
End: task.End,
})
}
return
}
package service
import (
apiModel "sdk_api/model/api"
dbModel "sdk_api/model/db"
"sdk_api/util"
log "github.com/sirupsen/logrus"
)
func (s *Service) CreateProject(req *apiModel.CreateProjectRequest) (pid int, err error) {
p := &dbModel.Project{
Id: util.GenFlakeID(),
Name: req.ProjectName,
TelegramChatId: req.TelegramChatId,
TwitterHandle: req.TwitterHandle,
}
err = s.d.CreateProject(p)
if err != nil {
log.WithError(err).Error("create project error")
return
}
return p.Id, nil
}
func (s *Service) GetProjectList(page, pageSize int) (resp []*apiModel.GetProjectResponse, err error) {
list, err := s.d.GetProjectList(page, pageSize)
if err != nil {
log.WithError(err).Error("get project list error")
return
}
resp = make([]*apiModel.GetProjectResponse, 0)
for _, v := range list {
resp = append(resp, &apiModel.GetProjectResponse{
ProjectName: v.Name,
TelegramChatId: v.TelegramChatId,
TwitterHandle: v.TwitterHandle,
})
}
return
}
func (s *Service) GetProject(pid int) (resp *apiModel.GetProjectResponse, err error) {
p, err := s.d.GetProject(pid)
if err != nil {
log.WithError(err).Error("get project error")
return
}
if p == nil {
log.WithError(err).Error("project not found")
return nil, nil
}
return &apiModel.GetProjectResponse{
ProjectName: p.Name,
TelegramChatId: p.TelegramChatId,
TwitterHandle: p.TwitterHandle,
}, nil
}
package service
import (
"sdk_api/config"
"sdk_api/dao"
)
type Service struct {
d *dao.Dao
cfg *config.Config
}
func New(conf *config.Config, da *dao.Dao) *Service {
return &Service{
d: da,
cfg: conf,
}
}
package service
package util
import (
"time"
"github.com/golang-jwt/jwt/v5"
)
const secret = "cxcZa005Y5zWH1wFgXvPGDL02Ey4ZCLAh2XFcfp7HhG3wTg5TbcnhuYhNvN3YLgt"
func GenerateJWT(uid, platform, platformId string) string {
tk := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
"uid": uid,
"platform": platform,
"platformId": platformId,
"iat": time.Now().Unix(),
"exp": time.Now().Add(7 * 24 * time.Hour).Unix(),
})
j, _ := tk.SignedString([]byte(secret))
return j
}
func ParseJWT(token string) (ok, expired bool, uid, platform, platformId string) {
claims := jwt.MapClaims{}
tk, err := jwt.ParseWithClaims(token, claims, func(t *jwt.Token) (interface{}, error) {
return []byte(secret), nil
})
if err != nil {
return
}
if !tk.Valid {
return
}
uid = claims["uid"].(string)
platform = claims["platform"].(string)
platformId = claims["platformId"].(string)
exp := claims["exp"].(float64)
if time.Now().Unix() > int64(exp) {
expired = true
return
}
ok = true
return
}
package util
import (
"testing"
)
func TestA(t *testing.T) {
token := GenerateJWT("12345", "telegram", "0x12345")
t.Logf("token: %s", token)
ParseJWT(token)
}
func TestB(t *testing.T) {
t.Log(ParseJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MTgwMTU2MTQsImlhdCI6MTcxNzQxMDgxNCwicGxhdGZvcm0iOiJ0ZWxlZ3JhbSIsInBsYXRmb3JtSWQiOiIweDEyMzQ1IiwidWlkIjoiMTIzNDUifQ.yZ1V_cGozBrwK55Y9iZsG4C-B5T96V2E3-AqP6CqkR8"))
}
package util
import (
"github.com/bwmarrin/snowflake"
)
var node *snowflake.Node
func init() {
node, _ = snowflake.NewNode(1)
}
func GenFlakeID() int {
return int(node.Generate().Int64())
}
package util
import (
"crypto/hmac"
"crypto/sha256"
"fmt"
"net/url"
"sort"
"strconv"
"strings"
"time"
"github.com/tidwall/gjson"
)
func VerifyInitData(initData, botToken string) (ok bool, botId, userId string) {
h := hmac.New(sha256.New, []byte("WebAppData"))
h.Write([]byte(botToken))
secret := h.Sum(nil)
h2 := hmac.New(sha256.New, secret)
params, err := url.ParseQuery(initData)
if err != nil {
return
}
var hashval string
var keys []string
for key := range params {
if key == "hash" {
hashval = params.Get(key)
continue
}
if key == "auth_date" {
authDate, _ := strconv.Atoi(params.Get(key))
if int64(authDate) < time.Now().Unix()-3600 || int64(authDate) > time.Now().Unix()+300 {
// todo 可以限制超时时间
return false, "", ""
}
}
if key == "user" {
userId = gjson.Get(params.Get(key), "id").String()
}
keys = append(keys, key)
}
sort.Strings(keys)
var payloads []string
for _, key := range keys {
payloads = append(payloads, fmt.Sprintf("%s=%s", key, params.Get(key)))
}
payload := strings.Join(payloads, "\n")
h2.Write([]byte(payload))
h2sum := h2.Sum(nil)
items := strings.Split(botToken, ":")
if len(items) != 2 {
return
}
ok = fmt.Sprintf("%x", h2sum) == hashval
botId = items[0]
return
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment