Compare commits

...

13 Commits

Author SHA1 Message Date
alfred-mk
1d07d7fb1d updated README 2024-11-08 20:35:17 +03:00
a3e5aab6c4 Merge pull request 'Africastalking POST route' (#168) from africastalking-endpoint into master
Reviewed-on: urdt/ussd#168
2024-11-08 17:25:46 +01:00
alfred-mk
574807d254 set the africastalking POST route using env 2024-11-08 16:52:19 +03:00
carlos
256ed6491b Merge pull request 'http-logs' (#167) from http-logs into master
Reviewed-on: urdt/ussd#167
2024-11-08 12:51:30 +01:00
carlos
7a02ffcf0c Merge pull request 'log-file' (#166) from log-file into http-logs
Reviewed-on: urdt/ussd#166
2024-11-08 08:09:15 +01:00
Carlosokumu
dcd8fce59a add log on create account 2024-11-08 10:07:06 +03:00
alfred-mk
64a7b49218 Remove unused Warning logger 2024-11-08 00:21:11 +03:00
alfred-mk
1bcbb2079e Removed unused variable 2024-11-08 00:17:02 +03:00
alfred-mk
e63468433e Merge branch 'http-logs' into log-file 2024-11-08 00:14:34 +03:00
alfred-mk
9c972ffa6b add specific log files per binary 2024-11-07 16:46:12 +03:00
alfred-mk
a11776e1b3 ignore .log files 2024-11-07 16:41:38 +03:00
Carlosokumu
6ac9ac29d8 add simple http logging 2024-11-07 16:41:08 +03:00
46b2b354fd Merge pull request 'swahili-templates-menu' (#158) from swahili-templates-menu into master
Reviewed-on: urdt/ussd#158
Reviewed-by: Alfred Kamanda <alfredkamandamw@gmail.com>
2024-11-05 11:29:07 +01:00
8 changed files with 221 additions and 19 deletions

View File

@@ -16,3 +16,6 @@ CREATE_ACCOUNT_URL=http://localhost:5003/api/v2/account/create
TRACK_STATUS_URL=https://custodial.sarafu.africa/api/track/
BALANCE_URL=https://custodial.sarafu.africa/api/account/status/
TRACK_URL=http://localhost:5003/api/v2/account/status
#AfricasTalking USSD POST endpoint
AT_ENDPOINT=/ussd/africastalking

1
.gitignore vendored
View File

@@ -6,3 +6,4 @@ go.work*
cmd/.state/
id_*
*.gdbm
*.log

View File

@@ -1,8 +1,91 @@
# ussd
# URDT USSD service
> USSD
This is a USSD service built using the [go-vise](https://github.com/nolash/go-vise) engine.
USSD service.
## Prerequisites
### 1. [go-vise](https://github.com/nolash/go-vise)
Set up `go-vise` by cloning the repository into a separate directory. The main upstream repository is hosted at: `https://git.defalsify.org/vise.git`
```
git clone https://git.defalsify.org/vise.git
```
## Setup
1. Clone the ussd repo in its own directory
```
git clone https://git.grassecon.net/urdt/ussd.git
```
2. Navigate to the project directory.
3. Enter the `services/registration` subfolder:
```
cd services/registration
```
4. make the .bin files from the .vis files
```
make VISE_PATH=/var/path/to/your/go-vise -B
```
5. Return to the project root (`cd ../..`)
6. Run the USSD menu
```
go run cmd/main.go -session-id=0712345678
```
## Running the different binaries
1. ### CLI:
```
go run cmd/main.go -session-id=0712345678
```
2. ### Africastalking:
```
go run cmd/africastalking/main.go
```
3. ### Async:
```
go run cmd/async/main.go
```
4. ### Http:
```
go run cmd/http/main.go
```
## Flags
Below are the supported flags:
1. `-session-id`:
Specifies the session ID. (CLI only).
Default: `075xx2123`.
Example:
```
go run cmd/main.go -session-id=0712345678
```
2. `-d`:
Enables engine debug output.
Default: `false`.
Example:
```
go run cmd/main.go -session-id=0712345678 -d
```
3. `-db`:
Specifies the database type.
Default: `gdbm`.
Example:
```
go run cmd/main.go -session-id=0712345678 -d -db=postgres
```
>Note: If using `-db=postgres`, ensure PostgreSQL is running with the connection details specified in your `.env` file.
## License

View File

@@ -1,9 +1,13 @@
package main
import (
"bytes"
"context"
"encoding/json"
"flag"
"fmt"
"io"
"log"
"net/http"
"os"
"os/signal"
@@ -25,12 +29,28 @@ import (
)
var (
logg = logging.NewVanilla()
scriptDir = path.Join("services", "registration")
logg = logging.NewVanilla()
scriptDir = path.Join("services", "registration")
InfoLogger *log.Logger
ErrorLogger *log.Logger
)
func init() {
initializers.LoadEnvVariables()
logFile := "urdt-ussd-africastalking.log"
file, err := os.OpenFile(logFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0666)
if err != nil {
log.Fatal(err)
}
InfoLogger = log.New(file, "INFO: ", log.Ldate|log.Ltime|log.Lshortfile)
ErrorLogger = log.New(file, "ERROR: ", log.Ldate|log.Ltime|log.Lshortfile)
// Inject into remote package
remote.InfoLogger = InfoLogger
remote.ErrorLogger = ErrorLogger
}
type atRequestParser struct{}
@@ -38,9 +58,30 @@ type atRequestParser struct{}
func (arp *atRequestParser) GetSessionId(rq any) (string, error) {
rqv, ok := rq.(*http.Request)
if !ok {
ErrorLogger.Println("got an invalid request:", rq)
return "", handlers.ErrInvalidRequest
}
// Capture body (if any) for logging
body, err := io.ReadAll(rqv.Body)
if err != nil {
ErrorLogger.Println("failed to read request body:", err)
return "", fmt.Errorf("failed to read request body: %v", err)
}
// Reset the body for further reading
rqv.Body = io.NopCloser(bytes.NewReader(body))
// Log the body as JSON
bodyLog := map[string]string{"body": string(body)}
logBytes, err := json.Marshal(bodyLog)
if err != nil {
ErrorLogger.Println("failed to marshal request body:", err)
} else {
InfoLogger.Println("Received request:", string(logBytes))
}
if err := rqv.ParseForm(); err != nil {
ErrorLogger.Println("failed to parse form data: %v", err)
return "", fmt.Errorf("failed to parse form data: %v", err)
}
@@ -156,9 +197,13 @@ func main() {
rp := &atRequestParser{}
bsh := handlers.NewBaseSessionHandler(cfg, rs, stateStore, userdataStore, rp, hl)
sh := httpserver.NewATSessionHandler(bsh)
mux := http.NewServeMux()
mux.Handle(initializers.GetEnv("AT_ENDPOINT", "/"), sh)
s := &http.Server{
Addr: fmt.Sprintf("%s:%s", host, strconv.Itoa(int(port))),
Handler: sh,
Handler: mux,
}
s.RegisterOnShutdown(sh.Shutdown)

View File

@@ -4,6 +4,7 @@ import (
"context"
"flag"
"fmt"
"log"
"os"
"os/signal"
"path"
@@ -23,12 +24,27 @@ import (
var (
logg = logging.NewVanilla()
scriptDir = path.Join("services", "registration")
InfoLogger *log.Logger
ErrorLogger *log.Logger
)
func init() {
initializers.LoadEnvVariables()
}
logFile := "urdt-ussd-async.log"
file, err := os.OpenFile(logFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0666)
if err != nil {
log.Fatal(err)
}
InfoLogger = log.New(file, "INFO: ", log.Ldate|log.Ltime|log.Lshortfile)
ErrorLogger = log.New(file, "ERROR: ", log.Ldate|log.Ltime|log.Lshortfile)
// Inject into remote package
remote.InfoLogger = InfoLogger
remote.ErrorLogger = ErrorLogger
}
type asyncRequestParser struct {
sessionId string
input []byte

View File

@@ -4,6 +4,7 @@ import (
"context"
"flag"
"fmt"
"log"
"net/http"
"os"
"os/signal"
@@ -26,10 +27,26 @@ import (
var (
logg = logging.NewVanilla()
scriptDir = path.Join("services", "registration")
InfoLogger *log.Logger
ErrorLogger *log.Logger
)
func init() {
initializers.LoadEnvVariables()
logFile := "urdt-ussd-http.log"
file, err := os.OpenFile(logFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0666)
if err != nil {
log.Fatal(err)
}
InfoLogger = log.New(file, "INFO: ", log.Ldate|log.Ltime|log.Lshortfile)
ErrorLogger = log.New(file, "ERROR: ", log.Ldate|log.Ltime|log.Lshortfile)
// Inject into remote package
remote.InfoLogger = InfoLogger
remote.ErrorLogger = ErrorLogger
}
func main() {

View File

@@ -4,6 +4,7 @@ import (
"context"
"flag"
"fmt"
"log"
"os"
"path"
@@ -20,10 +21,26 @@ import (
var (
logg = logging.NewVanilla()
scriptDir = path.Join("services", "registration")
InfoLogger *log.Logger
ErrorLogger *log.Logger
)
func init() {
initializers.LoadEnvVariables()
logFile := "urdt-ussd-cli.log"
file, err := os.OpenFile(logFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0666)
if err != nil {
log.Fatal(err)
}
InfoLogger = log.New(file, "INFO: ", log.Ldate|log.Ltime|log.Lshortfile)
ErrorLogger = log.New(file, "ERROR: ", log.Ldate|log.Ltime|log.Lshortfile)
// Inject into remote package
remote.InfoLogger = InfoLogger
remote.ErrorLogger = ErrorLogger
}
func main() {

View File

@@ -1,20 +1,24 @@
package remote
import (
"bytes"
"context"
"encoding/json"
"errors"
"io"
"log"
"net/http"
"net/url"
dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api"
"github.com/grassrootseconomics/eth-custodial/pkg/api"
"git.grassecon.net/urdt/ussd/config"
"git.grassecon.net/urdt/ussd/models"
"github.com/grassrootseconomics/eth-custodial/pkg/api"
dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api"
)
var (
InfoLogger *log.Logger
ErrorLogger *log.Logger
)
type AccountServiceInterface interface {
@@ -51,7 +55,7 @@ func (as *AccountService) TrackAccountStatus(ctx context.Context, publicKey stri
return nil, err
}
_, err = doCustodialRequest(ctx, req, &r)
_, err = doCustodialRequest(ctx, req, &r)
if err != nil {
return nil, err
}
@@ -79,7 +83,6 @@ func (as *AccountService) CheckBalance(ctx context.Context, publicKey string) (*
return &balanceResult, err
}
// CreateAccount creates a new account in the custodial system.
// Returns:
// - *models.AccountResponse: A pointer to an AccountResponse struct containing the details of the created account.
@@ -93,9 +96,9 @@ func (as *AccountService) CreateAccount(ctx context.Context) (*models.AccountRes
if err != nil {
return nil, err
}
_, err = doCustodialRequest(ctx, req, &r)
_, err = doCustodialRequest(ctx, req, &r)
if err != nil {
log.Printf("Failed to make custodial %s request to endpoint: %s with reason: %s", req.Method, req.URL, err.Error())
return nil, err
}
@@ -118,7 +121,7 @@ func (as *AccountService) FetchVouchers(ctx context.Context, publicKey string) (
return nil, err
}
_, err = doDataRequest(ctx, req, r)
_, err = doDataRequest(ctx, req, r)
if err != nil {
return nil, err
}
@@ -126,7 +129,6 @@ func (as *AccountService) FetchVouchers(ctx context.Context, publicKey string) (
return r, nil
}
// FetchTransactions retrieves the last 10 transactions for a given public key from the data indexer API endpoint
// Parameters:
// - publicKey: The public key associated with the account.
@@ -143,7 +145,7 @@ func (as *AccountService) FetchTransactions(ctx context.Context, publicKey strin
return nil, err
}
_, err = doDataRequest(ctx, req, r)
_, err = doDataRequest(ctx, req, r)
if err != nil {
return nil, err
}
@@ -151,7 +153,6 @@ func (as *AccountService) FetchTransactions(ctx context.Context, publicKey strin
return r, nil
}
// VoucherData retrieves voucher metadata from the data indexer API endpoint.
// Parameters:
// - address: The voucher address.
@@ -173,9 +174,8 @@ func (as *AccountService) VoucherData(ctx context.Context, address string) (*mod
}
func doRequest(ctx context.Context, req *http.Request, rcpt any) (*api.OKResponse, error) {
var okResponse api.OKResponse
var okResponse api.OKResponse
var errResponse api.ErrResponse
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
@@ -184,6 +184,7 @@ func doRequest(ctx context.Context, req *http.Request, rcpt any) (*api.OKRespons
}
defer resp.Body.Close()
InfoLogger.Printf("Received response for %s: Status Code: %d | Content-Type: %s", req.URL, resp.StatusCode, resp.Header.Get("Content-Type"))
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
@@ -214,10 +215,29 @@ func doRequest(ctx context.Context, req *http.Request, rcpt any) (*api.OKRespons
func doCustodialRequest(ctx context.Context, req *http.Request, rcpt any) (*api.OKResponse, error) {
req.Header.Set("X-GE-KEY", config.CustodialAPIKey)
logRequestDetails(req)
return doRequest(ctx, req, rcpt)
}
func doDataRequest(ctx context.Context, req *http.Request, rcpt any) (*api.OKResponse, error) {
req.Header.Set("X-GE-KEY", config.DataAPIKey)
logRequestDetails(req)
return doRequest(ctx, req, rcpt)
}
func logRequestDetails(req *http.Request) {
var bodyBytes []byte
contentType := req.Header.Get("Content-Type")
if req.Body != nil {
bodyBytes, err := io.ReadAll(req.Body)
if err != nil {
ErrorLogger.Printf("Error reading request body: %s", err)
return
}
req.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
} else {
bodyBytes = []byte("-")
}
InfoLogger.Printf("URL: %s | Content-Type: %s | Method: %s| Request Body: %s", req.URL, contentType, req.Method, string(bodyBytes))
}