mirror of
https://github.com/therootcompany/golib.git
synced 2026-03-02 23:57:59 +00:00
feat: add cmd/smsgwhookstocsv for smsapid (android sms gateway) jsonl to tsv
This commit is contained in:
parent
71eceb809f
commit
af6b0eb5a2
5
cmd/smsgwhookstocsv/go.mod
Normal file
5
cmd/smsgwhookstocsv/go.mod
Normal file
@ -0,0 +1,5 @@
|
||||
module github.com/therootcompany/golib/cmd/smsgwhookstocsv
|
||||
|
||||
go 1.25.0
|
||||
|
||||
require github.com/jszwec/csvutil v1.10.0
|
||||
2
cmd/smsgwhookstocsv/go.sum
Normal file
2
cmd/smsgwhookstocsv/go.sum
Normal file
@ -0,0 +1,2 @@
|
||||
github.com/jszwec/csvutil v1.10.0 h1:upMDUxhQKqZ5ZDCs/wy+8Kib8rZR8I8lOR34yJkdqhI=
|
||||
github.com/jszwec/csvutil v1.10.0/go.mod h1:/E4ONrmGkwmWsk9ae9jpXnv9QT8pLHEPcCirMFhxG9I=
|
||||
133
cmd/smsgwhookstocsv/main.go
Normal file
133
cmd/smsgwhookstocsv/main.go
Normal file
@ -0,0 +1,133 @@
|
||||
// smsgwhooks-to-tsv - Converts messages.jsonl webhook events to TSV/CSV
|
||||
//
|
||||
// Authored in 2026 by AJ ONeal <aj@therootcompany.com>, assisted by Grok Ai.
|
||||
// To the extent possible under law, the author(s) have dedicated all copyright
|
||||
// and related and neighboring rights to this software to the public domain
|
||||
// worldwide. This software is distributed without any warranty.
|
||||
//
|
||||
// You should have received a copy of the CC0 Public Domain Dedication along with
|
||||
// this software. If not, see <https://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/csv"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/jszwec/csvutil"
|
||||
)
|
||||
|
||||
type SmsReceivedPayload struct {
|
||||
Message string `json:"message" csv:"message"`
|
||||
MessageID string `json:"messageId" csv:"messageId"`
|
||||
PhoneNumber string `json:"phoneNumber" csv:"phoneNumber"`
|
||||
ReceivedAt string `json:"receivedAt" csv:"receivedAt"`
|
||||
SimNumber int `json:"simNumber" csv:"simNumber"`
|
||||
}
|
||||
|
||||
type WebhookEvent struct {
|
||||
DeviceID string `json:"deviceId" csv:"deviceId"`
|
||||
Event string `json:"event" csv:"event"`
|
||||
ID string `json:"id" csv:"id"`
|
||||
Payload SmsReceivedPayload `json:"payload" csv:",inline"`
|
||||
WebhookID string `json:"webhookId" csv:"webhookId"`
|
||||
XSignature string `json:"x-signature" csv:"x-signature"`
|
||||
XTimestamp int64 `json:"x-timestamp" csv:"x-timestamp"`
|
||||
}
|
||||
|
||||
type MainConfig struct {
|
||||
out string
|
||||
comma string
|
||||
in string
|
||||
}
|
||||
|
||||
func main() {
|
||||
cfg := MainConfig{}
|
||||
|
||||
fs := flag.NewFlagSet("smsgwhooks-to-tsv", flag.ExitOnError)
|
||||
|
||||
fs.StringVar(&cfg.out, "o", "-", "output file ('-' = stdout)")
|
||||
fs.StringVar(&cfg.comma, "comma", "\t", "field separator (default: tab)")
|
||||
|
||||
fs.Usage = func() {
|
||||
fmt.Fprintf(os.Stderr, "Usage: jsonl-to-tsv [flags] [input.jsonl]\n")
|
||||
fmt.Fprintf(os.Stderr, "\n")
|
||||
fmt.Fprintf(os.Stderr, "Converts JSONL webhook events to TSV (or CSV with custom separator).\n")
|
||||
fmt.Fprintf(os.Stderr, "\n")
|
||||
fmt.Fprintf(os.Stderr, "Flags:\n")
|
||||
fs.PrintDefaults()
|
||||
fmt.Fprintf(os.Stderr, "\n")
|
||||
fmt.Fprintf(os.Stderr, "Examples:\n")
|
||||
fmt.Fprintf(os.Stderr, " jsonl-to-tsv messages.jsonl\n")
|
||||
fmt.Fprintf(os.Stderr, " cat messages.jsonl | jsonl-to-tsv -\n")
|
||||
fmt.Fprintf(os.Stderr, " jsonl-to-tsv -o ./out.tsv messages.jsonl\n")
|
||||
fmt.Fprintf(os.Stderr, " jsonl-to-tsv --comma , -o ./out.csv messages.jsonl\n")
|
||||
fmt.Fprintf(os.Stderr, " jsonl-to-tsv -o - messages.jsonl # explicit stdout\n")
|
||||
}
|
||||
|
||||
_ = fs.Parse(os.Args[1:])
|
||||
|
||||
fi, _ := os.Stdin.Stat()
|
||||
isProbablyPipe := (fi.Mode() & os.ModeCharDevice) == 0
|
||||
if fs.NArg() == 0 && !isProbablyPipe {
|
||||
fs.Usage()
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
var in io.Reader = os.Stdin
|
||||
if cfg.in = fs.Arg(0); cfg.in != "" && cfg.in != "-" {
|
||||
f, err := os.Open(cfg.in)
|
||||
if err != nil {
|
||||
log.Fatalf("open input: %v", err)
|
||||
}
|
||||
defer func() { _ = f.Close() }()
|
||||
in = f
|
||||
}
|
||||
|
||||
var out io.Writer = os.Stdout
|
||||
if cfg.out != "-" {
|
||||
f, err := os.Create(cfg.out)
|
||||
if err != nil {
|
||||
log.Fatalf("create output: %v", err)
|
||||
}
|
||||
defer func() { _ = f.Close() }()
|
||||
out = f
|
||||
}
|
||||
|
||||
csvWriter := csv.NewWriter(out)
|
||||
csvWriter.Comma = rune((cfg.comma)[0])
|
||||
csvWriter.UseCRLF = false
|
||||
|
||||
enc := csvutil.NewEncoder(csvWriter)
|
||||
|
||||
// write header
|
||||
_ = enc.EncodeHeader(WebhookEvent{})
|
||||
|
||||
dec := json.NewDecoder(in)
|
||||
for dec.More() {
|
||||
var evt WebhookEvent
|
||||
if err := dec.Decode(&evt); err != nil {
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
log.Printf("decode error, skipping: %v", err)
|
||||
continue
|
||||
}
|
||||
if evt.Event != "sms:received" {
|
||||
continue
|
||||
}
|
||||
|
||||
if err := enc.Encode(evt); err != nil {
|
||||
log.Fatalf("encode error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
csvWriter.Flush()
|
||||
if err := csvWriter.Error(); err != nil {
|
||||
log.Printf("flush error: %v", err)
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user