diff --git a/cmd/server/main.go b/cmd/server/main.go index def68a5..86399fd 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -2,9 +2,11 @@ package main import ( "context" + "log" "log/slog" "os" "os/signal" + "syscall" "github.com/google/uuid" "github.com/pkg/errors" @@ -16,7 +18,9 @@ import ( "github.com/iotexproject/pebble-server/cmd/server/api" "github.com/iotexproject/pebble-server/cmd/server/clients" "github.com/iotexproject/pebble-server/cmd/server/commands" + "github.com/iotexproject/pebble-server/cmd/server/config" "github.com/iotexproject/pebble-server/contexts" + "github.com/iotexproject/pebble-server/db" "github.com/iotexproject/pebble-server/middlewares/alert" "github.com/iotexproject/pebble-server/middlewares/blockchain" "github.com/iotexproject/pebble-server/middlewares/crypto" @@ -34,8 +38,8 @@ var ( CommitID string Date string - app *confapp.AppCtx - config = &struct { + app *confapp.AppCtx + config1 = &struct { DryRun bool MqttBroker *confmqtt.Broker Database *database.Postgres @@ -183,9 +187,19 @@ func Main() error { } func main() { - if err := app.Command.Execute(); err != nil { - app.PrintErrln(err) + cfg, err := config.Get() + if err != nil { + log.Fatal(errors.Wrap(err, "failed to get config")) } - config.Blockchain.Close() - os.Exit(-1) + cfg.Print() + slog.Info("pebble server config loaded") + + db, err := db.New(cfg.DatabaseDSN) + if err != nil { + log.Fatal(errors.Wrap(err, "failed to new db")) + } + + done := make(chan os.Signal, 1) + signal.Notify(done, syscall.SIGINT, syscall.SIGTERM) + <-done } diff --git a/db/account.go b/db/account.go new file mode 100644 index 0000000..6bf3208 --- /dev/null +++ b/db/account.go @@ -0,0 +1,11 @@ +package db + +type Account struct { + ID string `gorm:"primary_key"` + Name string `gorm:"not null"` + Avatar string `gorm:"not null"` + + OperationTimes +} + +func (*Account) TableName() string { return "account" } diff --git a/db/app.go b/db/app.go new file mode 100644 index 0000000..e6e86c9 --- /dev/null +++ b/db/app.go @@ -0,0 +1,13 @@ +package db + +type App struct { + ID string `gorm:"primary_key"` + Version string `gorm:"not null;default:''"` + Uri string `gorm:"not null;default:''"` + Avatar string `gorm:"not null;default:''"` + Content string `gorm:"not null;default:''"` + + OperationTimes +} + +func (*App) TableName() string { return "app" } diff --git a/db/appv2.go b/db/appv2.go new file mode 100644 index 0000000..260f25d --- /dev/null +++ b/db/appv2.go @@ -0,0 +1,24 @@ +package db + +type AppV2 struct { + ID string `gorm:"primary_key"` + Slug string `gorm:"not null;default:''"` + Logo string `gorm:"not null;default:''"` + Author string `gorm:"not null;default:''"` + Status string `gorm:"not null;default:''"` + Content string `gorm:"not null;default:''"` + Data string `gorm:"not null;default:'{}'"` + Previews string `gorm:"not null;default:'[]'"` + Date string `gorm:"not null;default:''"` + CreatedAt string `gorm:"not null;default:''"` + UpdatedAt string `gorm:"not null;default:''"` + URI string `gorm:"not null;default:''"` + Category int32 `gorm:"not null;default:0"` + DirectLink string `gorm:"not null;default:''"` + Order int32 `gorm:"not null;default:0"` + Firmware string `gorm:"not null;default:''"` + + OperationTimes +} + +func (*AppV2) TableName() string { return "app_v2" } diff --git a/db/bank.go b/db/bank.go new file mode 100644 index 0000000..c1929dc --- /dev/null +++ b/db/bank.go @@ -0,0 +1,10 @@ +package db + +type Bank struct { + Address string `gorm:"primary_key"` + Balance string `gorm:"not null;default:'0'"` + + OperationTimes +} + +func (*Bank) TableName() string { return "bank" } diff --git a/db/bank_record.go b/db/bank_record.go new file mode 100644 index 0000000..2301a9e --- /dev/null +++ b/db/bank_record.go @@ -0,0 +1,20 @@ +package db + +const ( + BankRecodeDeposit int32 = iota + BankRecodeWithdraw + BankRecodePaid +) + +type BankRecord struct { + ID string `gorm:"primary_key"` + From string `gorm:"not null;default:''"` + To string `gorm:"not null;default:''"` + Amount string `gorm:"not null;default:''"` + Timestamp int64 `gorm:"not null;default:0"` + Type int32 `gorm:"not null;default:0"` + + OperationTimes +} + +func (*BankRecord) TableName() string { return "bank_record" } diff --git a/db/device.go b/db/device.go new file mode 100644 index 0000000..55a6100 --- /dev/null +++ b/db/device.go @@ -0,0 +1,34 @@ +package db + +const ( + CREATED int32 = iota + PROPOSAL + CONFIRM +) + +type Device struct { + ID string `gorm:"primary_key"` + Name string `gorm:"not null;default:''"` + Owner string `gorm:"not null;default:''"` + Address string `gorm:"not null;default:''"` + Avatar string `gorm:"not null;default:''"` + Status int32 `gorm:"not null;default:0"` + Proposer string `gorm:"not null;default:''"` + Firmware string `gorm:"not null;default:''"` + Config string `gorm:"not null;default:''"` + TotalGas int32 `gorm:"not null;default:0"` + BulkUpload int32 `gorm:"not null;default:0"` + DataChannel int32 `gorm:"not null;default:0"` + UploadPeriod int32 `gorm:"not null;default:0"` + BulkUploadSamplingCnt int32 `gorm:"not null;default:0"` + BulkUploadSamplingFreq int32 `gorm:"not null;default:0"` + Beep int32 `gorm:"not null;default:0"` + RealFirmware string `gorm:"not null;default:''"` + State int32 `gorm:"not null;default:0"` + Type int32 `gorm:"not null;default:0"` + Configurable bool `gorm:"not null;default:0;default:true"` + + OperationTimes +} + +func (*Device) TableName() string { return "device" } diff --git a/db/device_record.go b/db/device_record.go new file mode 100644 index 0000000..c63b8bb --- /dev/null +++ b/db/device_record.go @@ -0,0 +1,25 @@ +package db + +type DeviceRecord struct { + ID string `gorm:"primary_key"` + Imei string `gorm:"index:device_record_imei;not null"` + Operator string `gorm:"not null"` + Snr string `gorm:"not null;type:numeric(10,2);default:0"` + Vbat string `gorm:"not null;type:numeric(10,2);default:0"` + GasResistance string `gorm:"not null;type:numeric(10,2);default:0"` + Temperature string `gorm:"not null;type:numeric(10,2);default:0"` + Temperature2 string `gorm:"not null;type:numeric(10,2);default:0"` + Pressure string `gorm:"not null;type:numeric(10,2);default:0"` + Humidity string `gorm:"not null;type:numeric(10,2);default:0"` + Light string `gorm:"not null;type:numeric(10,2);default:0"` + Gyroscope string `gorm:"not null;default:''"` + Accelerometer string `gorm:"not null;default:''"` + Latitude string `gorm:"not null;default:0"` + Longitude string `gorm:"not null;default:0"` + Signature string `gorm:"not null;default:''"` + Timestamp int64 `gorm:"index:device_record_timestamp;not null;default:0"` + + OperationTimes +} + +func (*DeviceRecord) TableName() string { return "device_record" } diff --git a/db/message.go b/db/message.go new file mode 100644 index 0000000..33079f7 --- /dev/null +++ b/db/message.go @@ -0,0 +1,13 @@ +package db + +import "gorm.io/gorm" + +type Message struct { + gorm.Model + MessageID string `gorm:"index:message_id,not null"` + ClientID string `gorm:"index:message_fetch,not null,default:''"` + ProjectID uint64 `gorm:"index:message_fetch,not null"` + ProjectVersion string `gorm:"index:message_fetch,not null,default:'0.0'"` + Data []byte `gorm:"size:4096"` + InternalTaskID string `gorm:"index:internal_task_id,not null,default:''"` +} diff --git a/db/postgres.go b/db/postgres.go new file mode 100644 index 0000000..fa342e4 --- /dev/null +++ b/db/postgres.go @@ -0,0 +1,35 @@ +package db + +import ( + "github.com/pkg/errors" + "gorm.io/driver/postgres" + "gorm.io/gorm" + "gorm.io/gorm/logger" +) + +type DB struct { + db *gorm.DB +} + +func New(dsn string) (*DB, error) { + db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{ + Logger: logger.Default.LogMode(logger.Silent), + }) + if err != nil { + return nil, errors.Wrap(err, "failed to connect postgres") + } + if err := db.AutoMigrate( + &Account{}, + &App{}, + &AppV2{}, + &Bank{}, + &BankRecord{}, + &Device{}, + &DeviceRecord{}, + &Task{}, + &Message{}, + ); err != nil { + return nil, errors.Wrap(err, "failed to migrate model") + } + return &DB{db}, nil +} diff --git a/db/task.go b/db/task.go new file mode 100644 index 0000000..f0a78d5 --- /dev/null +++ b/db/task.go @@ -0,0 +1,40 @@ +package db + +import ( + "bytes" + "crypto/ecdsa" + "encoding/binary" + + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/crypto" + "github.com/pkg/errors" + "gorm.io/gorm" +) + +type Task struct { + gorm.Model + ProjectID uint64 `gorm:"index:task_fetch,not null"` + InternalTaskID string `gorm:"index:internal_task_id,not null"` + MessageIDs []byte `gorm:"not null"` + Signature string `gorm:"not null,default:''"` +} + +func (t *Task) Sign(sk *ecdsa.PrivateKey, msg *Message) error { + if msg.ProjectID != t.ProjectID { + return errors.New("unmatched project id") + } + + buf := bytes.NewBuffer(nil) + _ = binary.Write(buf, binary.BigEndian, uint64(t.ID)) + _ = binary.Write(buf, binary.BigEndian, t.ProjectID) + _, _ = buf.WriteString(msg.ClientID) + _, _ = buf.Write(crypto.Keccak256Hash(msg.Data).Bytes()) + + h := crypto.Keccak256Hash(buf.Bytes()) + sig, err := crypto.Sign(h.Bytes(), sk) + if err != nil { + return err + } + t.Signature = hexutil.Encode(sig) + return nil +} diff --git a/db/util.go b/db/util.go new file mode 100644 index 0000000..ef132ba --- /dev/null +++ b/db/util.go @@ -0,0 +1,15 @@ +package db + +import "time" + +func NewOperationTimes() OperationTimes { + return OperationTimes{ + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + } +} + +type OperationTimes struct { + CreatedAt time.Time `gorm:"not null"` + UpdatedAt time.Time `gorm:"not null"` +}