mirror of https://github.com/certusone/dc4bc.git
commit
64d74db35a
|
@ -95,18 +95,26 @@ func (c *Client) GetOperations() (map[string]*Operation, error) {
|
||||||
return c.state.GetOperations()
|
return c.state.GetOperations()
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetOperationQRPath returns a path to the image with the QR generated
|
func (c *Client) getOperationJSON(operationID string) ([]byte, error) {
|
||||||
// for the specified operation. It is supposed that the user will open
|
|
||||||
// this file herself.
|
|
||||||
func (c *Client) GetOperationQRPath(operationID string) (string, error) {
|
|
||||||
operation, err := c.state.GetOperationByID(operationID)
|
operation, err := c.state.GetOperationByID(operationID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("failed to get operation: %w", err)
|
return nil, fmt.Errorf("failed to get operation: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
operationJSON, err := json.Marshal(operation)
|
operationJSON, err := json.Marshal(operation)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("failed to marshal operation: %w", err)
|
return nil, fmt.Errorf("failed to marshal operation: %w", err)
|
||||||
|
}
|
||||||
|
return operationJSON, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetOperationQRPath returns a path to the image with the QR generated
|
||||||
|
// for the specified operation. It is supposed that the user will open
|
||||||
|
// this file herself.
|
||||||
|
func (c *Client) GetOperationQRPath(operationID string) (string, error) {
|
||||||
|
operationJSON, err := c.getOperationJSON(operationID)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("failed to get operation in JSON: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
operationQRPath := filepath.Join(QrCodesDir, operationID)
|
operationQRPath := filepath.Join(QrCodesDir, operationID)
|
||||||
|
@ -131,6 +139,10 @@ func (c *Client) ReadProcessedOperation() error {
|
||||||
return fmt.Errorf("failed to unmarshal processed operation")
|
return fmt.Errorf("failed to unmarshal processed operation")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return c.handleProcessedOperation(operation)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) handleProcessedOperation(operation Operation) error {
|
||||||
storedOperation, err := c.state.GetOperationByID(operation.ID)
|
storedOperation, err := c.state.GetOperationByID(operation.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to find matching operation: %w", err)
|
return fmt.Errorf("failed to find matching operation: %w", err)
|
||||||
|
|
|
@ -0,0 +1,179 @@
|
||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"image"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/depools/dc4bc/qr"
|
||||||
|
"github.com/depools/dc4bc/storage"
|
||||||
|
)
|
||||||
|
|
||||||
|
func errorResponse(w http.ResponseWriter, statusCode int, err string) {
|
||||||
|
log.Println(err)
|
||||||
|
w.WriteHeader(statusCode)
|
||||||
|
if _, err := w.Write([]byte(err)); err != nil {
|
||||||
|
panic(fmt.Sprintf("failed to write response: %v", err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func successResponse(w http.ResponseWriter, response []byte) {
|
||||||
|
if _, err := w.Write(response); err != nil {
|
||||||
|
panic(fmt.Sprintf("failed to write response: %v", err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) StartHTTPServer(listenAddr string) error {
|
||||||
|
http.HandleFunc("/sendMessage", c.sendMessageHandler)
|
||||||
|
http.HandleFunc("/getOperations", c.getOperationsHandler)
|
||||||
|
http.HandleFunc("/getOperationQRPath", c.getOperationQRPathHandler)
|
||||||
|
http.HandleFunc("/readProcessedOperationFromCamera", c.readProcessedOperationFromCameraHandler)
|
||||||
|
|
||||||
|
http.HandleFunc("/readProcessedOperation", c.readProcessedOperationFromBodyHandler)
|
||||||
|
http.HandleFunc("/getOperationQR", c.getOperationQRToBodyHandler)
|
||||||
|
return http.ListenAndServe(listenAddr, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) sendMessageHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.Method != http.MethodPost {
|
||||||
|
errorResponse(w, http.StatusBadRequest, "Wrong HTTP method")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
reqBytes, err := ioutil.ReadAll(r.Body)
|
||||||
|
if err != nil {
|
||||||
|
errorResponse(w, http.StatusBadRequest, fmt.Sprintf("failed to read request body: %v", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var msg storage.Message
|
||||||
|
if err = json.Unmarshal(reqBytes, &msg); err != nil {
|
||||||
|
errorResponse(w, http.StatusInternalServerError, fmt.Sprintf("failed to unmarshal message: %v", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = c.SendMessage(msg); err != nil {
|
||||||
|
errorResponse(w, http.StatusInternalServerError, fmt.Sprintf("failed to send message to the storage: %v", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
successResponse(w, []byte("ok"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) getOperationsHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.Method != http.MethodGet {
|
||||||
|
errorResponse(w, http.StatusBadRequest, "Wrong HTTP method")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
operations, err := c.GetOperations()
|
||||||
|
if err != nil {
|
||||||
|
errorResponse(w, http.StatusInternalServerError, fmt.Sprintf("failed to get operations: %v", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
response, err := json.Marshal(operations)
|
||||||
|
if err != nil {
|
||||||
|
errorResponse(w, http.StatusInternalServerError, fmt.Sprintf("failed to marshal operations: %v", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
successResponse(w, response)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) getOperationQRPathHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.Method != http.MethodGet {
|
||||||
|
errorResponse(w, http.StatusBadRequest, "Wrong HTTP method")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
operationID := r.URL.Query().Get("operationID")
|
||||||
|
|
||||||
|
qrPath, err := c.GetOperationQRPath(operationID)
|
||||||
|
if err != nil {
|
||||||
|
errorResponse(w, http.StatusInternalServerError, fmt.Sprintf("failed to get operation QR path: %v", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
successResponse(w, []byte(qrPath))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) getOperationQRToBodyHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.Method != http.MethodGet {
|
||||||
|
errorResponse(w, http.StatusBadRequest, "Wrong HTTP method")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
operationID := r.URL.Query().Get("operationID")
|
||||||
|
|
||||||
|
operationJSON, err := c.getOperationJSON(operationID)
|
||||||
|
if err != nil {
|
||||||
|
errorResponse(w, http.StatusInternalServerError, fmt.Sprintf("failed to get operation in JSON: %v", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
encodedData, err := qr.EncodeQR(operationJSON)
|
||||||
|
if err != nil {
|
||||||
|
errorResponse(w, http.StatusInternalServerError, fmt.Sprintf("failed to encode operation: %v", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "image/jpeg")
|
||||||
|
w.Header().Set("Content-Length", fmt.Sprintf("%d", len(encodedData)))
|
||||||
|
successResponse(w, encodedData)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) readProcessedOperationFromCameraHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.Method != http.MethodGet {
|
||||||
|
errorResponse(w, http.StatusBadRequest, "Wrong HTTP method")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.ReadProcessedOperation(); err != nil {
|
||||||
|
errorResponse(w, http.StatusInternalServerError,
|
||||||
|
fmt.Sprintf("failed to handle processed operation from camera path: %v", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
successResponse(w, []byte("ok"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) readProcessedOperationFromBodyHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.Method != http.MethodPost {
|
||||||
|
errorResponse(w, http.StatusBadRequest, "Wrong HTTP method")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := r.ParseMultipartForm(10 << 20); err != nil {
|
||||||
|
errorResponse(w, http.StatusInternalServerError, fmt.Sprintf("failed to parse multipat form: %v", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
file, _, err := r.FormFile("qr")
|
||||||
|
if err != nil {
|
||||||
|
errorResponse(w, http.StatusInternalServerError, fmt.Sprintf("failed to retrieve a file: %v", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
img, _, err := image.Decode(file)
|
||||||
|
if err != nil {
|
||||||
|
errorResponse(w, http.StatusInternalServerError, fmt.Sprintf("failed to decode an image: %v", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
qrData, err := qr.ReadDataFromQR(img)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var operation Operation
|
||||||
|
if err = json.Unmarshal(qrData, &operation); err != nil {
|
||||||
|
errorResponse(w, http.StatusInternalServerError,
|
||||||
|
fmt.Sprintf("failed to unmarshal processed operation: %v", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := c.handleProcessedOperation(operation); err != nil {
|
||||||
|
errorResponse(w, http.StatusInternalServerError, fmt.Sprintf("failed to handle an operation: %v", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,9 +1,10 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"log"
|
||||||
|
|
||||||
"github.com/depools/dc4bc/fsm/state_machines"
|
"github.com/depools/dc4bc/fsm/state_machines"
|
||||||
"github.com/depools/dc4bc/fsm/types/requests"
|
"github.com/depools/dc4bc/fsm/types/requests"
|
||||||
"log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
|
@ -8,6 +8,7 @@ const (
|
||||||
FSM1Name = "fsm1"
|
FSM1Name = "fsm1"
|
||||||
// Init process from global idle state
|
// Init process from global idle state
|
||||||
FSM1StateInit = StateGlobalIdle
|
FSM1StateInit = StateGlobalIdle
|
||||||
|
FSM2StateInit = StateGlobalIdle
|
||||||
// Set up data
|
// Set up data
|
||||||
FSM1StateStage1 = State("state_fsm1_stage1")
|
FSM1StateStage1 = State("state_fsm1_stage1")
|
||||||
// Process data
|
// Process data
|
||||||
|
|
|
@ -2,6 +2,7 @@ package fsm_pool
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"github.com/depools/dc4bc/fsm/fsm"
|
"github.com/depools/dc4bc/fsm/fsm"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ package state_machines
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"github.com/depools/dc4bc/fsm/fsm"
|
"github.com/depools/dc4bc/fsm/fsm"
|
||||||
"github.com/depools/dc4bc/fsm/fsm_pool"
|
"github.com/depools/dc4bc/fsm/fsm_pool"
|
||||||
"github.com/depools/dc4bc/fsm/state_machines/internal"
|
"github.com/depools/dc4bc/fsm/state_machines/internal"
|
||||||
|
|
|
@ -2,11 +2,12 @@ package signature_proposal_fsm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"log"
|
||||||
|
|
||||||
"github.com/depools/dc4bc/fsm/fsm"
|
"github.com/depools/dc4bc/fsm/fsm"
|
||||||
"github.com/depools/dc4bc/fsm/state_machines/internal"
|
"github.com/depools/dc4bc/fsm/state_machines/internal"
|
||||||
"github.com/depools/dc4bc/fsm/types/requests"
|
"github.com/depools/dc4bc/fsm/types/requests"
|
||||||
"github.com/depools/dc4bc/fsm/types/responses"
|
"github.com/depools/dc4bc/fsm/types/responses"
|
||||||
"log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// init -> awaitingConfirmations
|
// init -> awaitingConfirmations
|
||||||
|
|
|
@ -3,9 +3,10 @@ package signature_proposal_fsm
|
||||||
import (
|
import (
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
|
"math/rand"
|
||||||
|
|
||||||
"github.com/depools/dc4bc/fsm/state_machines/internal"
|
"github.com/depools/dc4bc/fsm/state_machines/internal"
|
||||||
"github.com/depools/dc4bc/fsm/types/responses"
|
"github.com/depools/dc4bc/fsm/types/responses"
|
||||||
"math/rand"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Request and response mutators
|
// Request and response mutators
|
||||||
|
|
|
@ -2,6 +2,7 @@ package requests
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"github.com/depools/dc4bc/fsm/config"
|
"github.com/depools/dc4bc/fsm/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -5,9 +5,10 @@
|
||||||
package clientMocks
|
package clientMocks
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
reflect "reflect"
|
||||||
|
|
||||||
client "github.com/depools/dc4bc/client"
|
client "github.com/depools/dc4bc/client"
|
||||||
gomock "github.com/golang/mock/gomock"
|
gomock "github.com/golang/mock/gomock"
|
||||||
reflect "reflect"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// MockState is a mock of State interface
|
// MockState is a mock of State interface
|
||||||
|
|
|
@ -5,9 +5,10 @@
|
||||||
package storageMocks
|
package storageMocks
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
reflect "reflect"
|
||||||
|
|
||||||
storage "github.com/depools/dc4bc/storage"
|
storage "github.com/depools/dc4bc/storage"
|
||||||
gomock "github.com/golang/mock/gomock"
|
gomock "github.com/golang/mock/gomock"
|
||||||
reflect "reflect"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// MockStorage is a mock of Storage interface
|
// MockStorage is a mock of Storage interface
|
||||||
|
|
32
qr/qr.go
32
qr/qr.go
|
@ -2,6 +2,7 @@ package qr
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"image"
|
||||||
"log"
|
"log"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -66,18 +67,7 @@ loop:
|
||||||
return nil, fmt.Errorf("failed to get image object: %w", err)
|
return nil, fmt.Errorf("failed to get image object: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
bmp, err := gozxing.NewBinaryBitmapFromImage(imgObject)
|
return ReadDataFromQR(imgObject)
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to get NewBinaryBitmapFromImage: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
qrReader := qrcode.NewQRCodeReader()
|
|
||||||
result, err := qrReader.Decode(bmp, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to decode the QR-code contents: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return result.GetRawBytes(), err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *CameraProcessor) WriteQR(path string, data []byte) error {
|
func (p *CameraProcessor) WriteQR(path string, data []byte) error {
|
||||||
|
@ -88,3 +78,21 @@ func (p *CameraProcessor) WriteQR(path string, data []byte) error {
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ReadDataFromQR(img image.Image) ([]byte, error) {
|
||||||
|
bmp, err := gozxing.NewBinaryBitmapFromImage(img)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get NewBinaryBitmapFromImage: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
qrReader := qrcode.NewQRCodeReader()
|
||||||
|
result, err := qrReader.Decode(bmp, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to decode the QR-code contents: %w", err)
|
||||||
|
}
|
||||||
|
return result.GetRawBytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func EncodeQR(data []byte) ([]byte, error) {
|
||||||
|
return encoder.Encode(string(data), encoder.Medium, 512)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue