initial commit
This commit is contained in:
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
main.go.bak
|
||||
go-npfd-printer
|
||||
/credentials/*
|
||||
config.yml
|
25
Dockerfile
Normal file
25
Dockerfile
Normal file
@ -0,0 +1,25 @@
|
||||
FROM golang:1.18.4-alpine3.16 AS builder
|
||||
|
||||
RUN apk update
|
||||
RUN apk add git
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY . ./
|
||||
COPY ./credentials/ ./app/credentials/
|
||||
COPY ./config.yml ./app
|
||||
|
||||
RUN go get -u . && \
|
||||
go build -o /app/go-npfd-printer ./
|
||||
|
||||
FROM alpine
|
||||
|
||||
WORKDIR /app
|
||||
COPY --from=builder /app/go-npfd-printer ./
|
||||
COPY --from=builder /app/credentials/ ./credentials/
|
||||
COPY --from=builder /app/config.yml ./config.yml
|
||||
|
||||
RUN apk add --no-cache tzdata
|
||||
ENV TZ=America/New_York
|
||||
|
||||
ENTRYPOINT [ "/app/go-npfd-printer" ]
|
18
config.yml.sample
Normal file
18
config.yml.sample
Normal file
@ -0,0 +1,18 @@
|
||||
mqtt:
|
||||
host: 10.10.10.77
|
||||
port: 1883
|
||||
username: printer
|
||||
password: U6wYZaJ0zL7witYE
|
||||
clientid: printer
|
||||
retained: false
|
||||
topic: "zwave/button_01/91/0/scene/001"
|
||||
postgres:
|
||||
host: 10.10.10.77
|
||||
port: 5432
|
||||
username: gonpfdprinter
|
||||
password: x85vr97qFU2o76Qp
|
||||
database: gonpfdprinter
|
||||
update: 30
|
||||
printer: /dev/usb/lp0
|
||||
log:
|
||||
level: info
|
63
go.mod
Normal file
63
go.mod
Normal file
@ -0,0 +1,63 @@
|
||||
module git.savin.nyc/alex/go-npfd-printer
|
||||
|
||||
go 1.23
|
||||
|
||||
require (
|
||||
github.com/eclipse/paho.mqtt.golang v1.5.0
|
||||
github.com/jackc/pgx/v4 v4.18.3
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
github.com/spf13/viper v1.19.0
|
||||
golang.org/x/net v0.34.0
|
||||
golang.org/x/oauth2 v0.25.0
|
||||
google.golang.org/api v0.219.0
|
||||
)
|
||||
|
||||
require (
|
||||
cloud.google.com/go/auth v0.14.1 // indirect
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.7 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.6.0 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/fsnotify/fsnotify v1.8.0 // indirect
|
||||
github.com/go-logr/logr v1.4.2 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/google/s2a-go v0.1.9 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.14.1 // indirect
|
||||
github.com/gorilla/websocket v1.5.3 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
|
||||
github.com/jackc/pgconn v1.14.3 // indirect
|
||||
github.com/jackc/pgio v1.0.0 // indirect
|
||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||
github.com/jackc/pgproto3/v2 v2.3.3 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
||||
github.com/jackc/pgtype v1.14.4 // indirect
|
||||
github.com/magiconair/properties v1.8.9 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
|
||||
github.com/sagikazarmark/locafero v0.7.0 // indirect
|
||||
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
|
||||
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||
github.com/spf13/afero v1.12.0 // indirect
|
||||
github.com/spf13/cast v1.7.1 // indirect
|
||||
github.com/spf13/pflag v1.0.6 // indirect
|
||||
github.com/subosito/gotenv v1.6.0 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0 // indirect
|
||||
go.opentelemetry.io/otel v1.34.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.34.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.34.0 // indirect
|
||||
go.uber.org/atomic v1.11.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
golang.org/x/crypto v0.32.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c // indirect
|
||||
golang.org/x/sync v0.10.0 // indirect
|
||||
golang.org/x/sys v0.29.0 // indirect
|
||||
golang.org/x/text v0.21.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250127172529-29210b9bc287 // indirect
|
||||
google.golang.org/grpc v1.70.0 // indirect
|
||||
google.golang.org/protobuf v1.36.4 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
297
go.sum
Normal file
297
go.sum
Normal file
@ -0,0 +1,297 @@
|
||||
cloud.google.com/go/auth v0.14.1 h1:AwoJbzUdxA/whv1qj3TLKwh3XX5sikny2fc40wUl+h0=
|
||||
cloud.google.com/go/auth v0.14.1/go.mod h1:4JHUxlGXisL0AW8kXPtUF6ztuOksyfUQNFjfsOCXkPM=
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.7 h1:/Lc7xODdqcEw8IrZ9SvwnlLX6j9FHQM74z6cBk9Rw6M=
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.7/go.mod h1:NTbTTzfvPl1Y3V1nPpOgl2w6d/FjO7NNUQaWSox6ZMc=
|
||||
cloud.google.com/go/compute v1.24.0 h1:phWcR2eWzRJaL/kOiJwfFsPs4BaKq1j6vnpZrc1YlVg=
|
||||
cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I=
|
||||
cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
|
||||
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
|
||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/eclipse/paho.mqtt.golang v1.5.0 h1:EH+bUVJNgttidWFkLLVKaQPGmkTUfQQqjOsyvMGvD6o=
|
||||
github.com/eclipse/paho.mqtt.golang v1.5.0/go.mod h1:du/2qNQVqJf/Sqs4MEL77kR8QTqANF7XU7Fk0aOTAgk=
|
||||
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
|
||||
github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
|
||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0=
|
||||
github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM=
|
||||
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/googleapis/enterprise-certificate-proxy v0.3.4 h1:XYIDZApgAnrN1c855gTgghdIA6Stxb52D5RnLI1SLyw=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.4/go.mod h1:YKe7cfqYXjKGpGvmSg28/fFvhNzinZQm8DGnaburhGA=
|
||||
github.com/googleapis/gax-go/v2 v2.14.1 h1:hb0FFeiPaQskmvakKu5EbCbpntQn48jyHuvrkurSS/Q=
|
||||
github.com/googleapis/gax-go/v2 v2.14.1/go.mod h1:Hb/NubMaVM88SrNkvl8X/o8XWwDJEPqouaLeN2IUxoA=
|
||||
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0=
|
||||
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
|
||||
github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
|
||||
github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8=
|
||||
github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
|
||||
github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA=
|
||||
github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE=
|
||||
github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s=
|
||||
github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o=
|
||||
github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY=
|
||||
github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI=
|
||||
github.com/jackc/pgconn v1.14.3 h1:bVoTr12EGANZz66nZPkMInAV/KHD2TxH9npjXXgiB3w=
|
||||
github.com/jackc/pgconn v1.14.3/go.mod h1:RZbme4uasqzybK2RK5c65VsHxoyaml09lx3tXOcO/VM=
|
||||
github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE=
|
||||
github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
|
||||
github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE=
|
||||
github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c=
|
||||
github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak=
|
||||
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/pgproto3 v1.1.0 h1:FYYE4yRw+AgI8wXIinMlNjBbp/UitDJwfj5LqqewP1A=
|
||||
github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78=
|
||||
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA=
|
||||
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg=
|
||||
github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
|
||||
github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
|
||||
github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
|
||||
github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
|
||||
github.com/jackc/pgproto3/v2 v2.3.3 h1:1HLSx5H+tXR9pW3in3zaztoEwQYRC9SQaYUHjTSUOag=
|
||||
github.com/jackc/pgproto3/v2 v2.3.3/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
|
||||
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
|
||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||
github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg=
|
||||
github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc=
|
||||
github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw=
|
||||
github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM=
|
||||
github.com/jackc/pgtype v1.14.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4=
|
||||
github.com/jackc/pgtype v1.14.4 h1:fKuNiCumbKTAIxQwXfB/nsrnkEI6bPJrrSiMKgbJ2j8=
|
||||
github.com/jackc/pgtype v1.14.4/go.mod h1:aKeozOde08iifGosdJpz9MBZonJOUJxqNpPBcMJTlVA=
|
||||
github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y=
|
||||
github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM=
|
||||
github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc=
|
||||
github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs=
|
||||
github.com/jackc/pgx/v4 v4.18.2/go.mod h1:Ey4Oru5tH5sB6tV7hDmfWFahwF15Eb7DNXlRKx2CkVw=
|
||||
github.com/jackc/pgx/v4 v4.18.3 h1:dE2/TrEsGX3RBprb3qryqSV9Y60iZN1C6i8IrmW9/BA=
|
||||
github.com/jackc/pgx/v4 v4.18.3/go.mod h1:Ey4Oru5tH5sB6tV7hDmfWFahwF15Eb7DNXlRKx2CkVw=
|
||||
github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM=
|
||||
github.com/magiconair/properties v1.8.9/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
|
||||
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
|
||||
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
|
||||
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
|
||||
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
|
||||
github.com/sagikazarmark/locafero v0.7.0 h1:5MqpDsTGNDhY8sGp0Aowyf0qKsPrhewaLSsFaodPcyo=
|
||||
github.com/sagikazarmark/locafero v0.7.0/go.mod h1:2za3Cg5rMaTMoG/2Ulr9AwtFaIppKXTRYnozin4aB5k=
|
||||
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
|
||||
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
|
||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
|
||||
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
|
||||
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
|
||||
github.com/spf13/afero v1.12.0 h1:UcOPyRBYczmFn6yvphxkn9ZEOY65cpwGKb5mL36mrqs=
|
||||
github.com/spf13/afero v1.12.0/go.mod h1:ZTlWwG4/ahT8W7T0WQ5uYmjI9duaLQGy3Q2OAl4sk/4=
|
||||
github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y=
|
||||
github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
||||
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
|
||||
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI=
|
||||
github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
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/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
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/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0 h1:CV7UdSGJt/Ao6Gp4CXckLxVRRsRgDHoI8XjbL3PDl8s=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0/go.mod h1:FRmFuRJfag1IZ2dPkHnEoSFVgTVPUd2qf5Vi69hLb8I=
|
||||
go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY=
|
||||
go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI=
|
||||
go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ=
|
||||
go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE=
|
||||
go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k=
|
||||
go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE=
|
||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
|
||||
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
|
||||
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
|
||||
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/crypto v0.20.0/go.mod h1:Xwo95rrVNIoSMx9wa1JroENMToLWn3RNVrTBpLHgZPQ=
|
||||
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
|
||||
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
|
||||
golang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c h1:KL/ZBHXgKGVmuZBZ01Lt57yE5ws8ZPSkkihmEyq7FXc=
|
||||
golang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
|
||||
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
|
||||
golang.org/x/oauth2 v0.25.0 h1:CY4y7XT9v0cRI9oupztF8AgiIu99L/ksR/Xp/6jrZ70=
|
||||
golang.org/x/oauth2 v0.25.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
|
||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
|
||||
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.219.0 h1:nnKIvxKs/06jWawp2liznTBnMRQBEPpGo7I+oEypTX0=
|
||||
google.golang.org/api v0.219.0/go.mod h1:K6OmjGm+NtLrIkHxv1U3a0qIf/0JOvAHd5O/6AoyKYE=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250127172529-29210b9bc287 h1:J1H9f+LEdWAfHcez/4cvaVBox7cOYT+IU6rgqj5x++8=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250127172529-29210b9bc287/go.mod h1:8BS3B93F/U1juMFq9+EDk+qOT5CO1R9IzXxG3PTqiRk=
|
||||
google.golang.org/grpc v1.70.0 h1:pWFv03aZoHzlRKHWicjsZytKAiYCtNS0dHbXnIdq7jQ=
|
||||
google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw=
|
||||
google.golang.org/protobuf v1.36.4 h1:6A3ZDJHn/eNqc1i+IdefRzy/9PokBTPvcqMySR7NNIM=
|
||||
google.golang.org/protobuf v1.36.4/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
|
||||
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
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=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
418
main.go
Normal file
418
main.go
Normal file
@ -0,0 +1,418 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"fmt"
|
||||
"html"
|
||||
"os"
|
||||
"os/signal"
|
||||
"regexp"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"git.savin.nyc/alex/go-npfd-printer/parser"
|
||||
"git.savin.nyc/alex/go-npfd-printer/printer"
|
||||
mqtt "github.com/eclipse/paho.mqtt.golang"
|
||||
"github.com/jackc/pgx/v4"
|
||||
logrus "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/viper"
|
||||
"google.golang.org/api/gmail/v1"
|
||||
)
|
||||
|
||||
var log = logrus.New()
|
||||
var config Config
|
||||
var conn *pgx.Conn
|
||||
var prntr *printer.Escpos
|
||||
var readerP *bufio.Reader
|
||||
var writerP *bufio.Writer
|
||||
var readWriter *bufio.ReadWriter
|
||||
var ctx context.Context
|
||||
|
||||
// Config .
|
||||
type Config struct {
|
||||
MQTT struct {
|
||||
Host string `json:"host"`
|
||||
Port int `json:"port"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
ClientId string `json:"clientid"`
|
||||
Retained bool `json:"retained"`
|
||||
Topic string `json:"topic"`
|
||||
} `json:"mqtt"`
|
||||
Postgres struct {
|
||||
Host string `json:"host"`
|
||||
Port int `json:"port"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
Database string `json:"database"`
|
||||
} `json:"postgres"`
|
||||
Update time.Duration `json:"update"`
|
||||
Printer string `json:"printer"`
|
||||
Log struct {
|
||||
Level string `json:"level"`
|
||||
} `json:"log"`
|
||||
}
|
||||
|
||||
// gMSG .
|
||||
type gMSG struct {
|
||||
gmailID string
|
||||
date string // retrieved from message header
|
||||
snippet string
|
||||
}
|
||||
|
||||
// mqttConnect .
|
||||
func mqttConnect(wg *sync.WaitGroup) mqtt.Client {
|
||||
opts := mqtt.NewClientOptions()
|
||||
opts.AddBroker(fmt.Sprintf("tcp://%s:%d", config.MQTT.Host, config.MQTT.Port))
|
||||
opts.SetUsername(config.MQTT.Username)
|
||||
opts.SetPassword(config.MQTT.Password)
|
||||
opts.SetClientID(config.MQTT.ClientId)
|
||||
// opts.OnConnect = func(m mqtt.Client) {
|
||||
// log.Printf("MQTT Client is connected to a MQTT Broker\n")
|
||||
// starter(wg, m)
|
||||
// }
|
||||
opts.OnConnect = func(m mqtt.Client) {
|
||||
log.Printf("MQTT Client is connected to a MQTT Broker\n")
|
||||
starter(wg, m)
|
||||
if token := m.Subscribe(config.MQTT.Topic, byte(0), onMessageReceived); token.Wait() && token.Error() != nil {
|
||||
panic(token.Error())
|
||||
}
|
||||
}
|
||||
client := mqtt.NewClient(opts)
|
||||
token := client.Connect()
|
||||
for !token.WaitTimeout(3 * time.Second) {
|
||||
}
|
||||
if err := token.Error(); err != nil {
|
||||
log.Fatalf("Couldn't connect to a MQTT Broker (%s)\n", err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
return client
|
||||
}
|
||||
|
||||
// onMessageReceived .
|
||||
func onMessageReceived(m mqtt.Client, message mqtt.Message) {
|
||||
log.Printf("TOPIC: %s\n", message.Topic())
|
||||
log.Printf("MSG: %s\n", message.Payload())
|
||||
re := regexp.MustCompile(`^\{\"time\"\:(?P<time>[0-9]*)(?:\,\"value\"\:)?(?P<value>[0-5]+)?\}$`)
|
||||
if re.Match([]byte(message.Payload())) {
|
||||
|
||||
groups := re.SubexpNames()
|
||||
result := re.FindAllStringSubmatch(string(message.Payload()), -1)
|
||||
|
||||
rt := map[string]string{}
|
||||
for i, n := range result[0] {
|
||||
rt[groups[i]] = n
|
||||
}
|
||||
log.Printf("PARESED MESSAGE: %+v\n", rt)
|
||||
if rt["value"] == "0" {
|
||||
log.Printf("LET'S PRINT IT\n")
|
||||
toPrinter()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// starter .
|
||||
func starter(wg *sync.WaitGroup, m mqtt.Client) {
|
||||
|
||||
log.Println("Executing a starter func connection...")
|
||||
|
||||
wg.Add(1)
|
||||
go scanner(wg, m)
|
||||
}
|
||||
|
||||
// reverse .
|
||||
func reverse(msgs []gMSG) []gMSG {
|
||||
newMsgs := make([]gMSG, 0, len(msgs))
|
||||
for i := len(msgs) - 1; i >= 0; i-- {
|
||||
newMsgs = append(newMsgs, msgs[i])
|
||||
}
|
||||
|
||||
return newMsgs
|
||||
}
|
||||
|
||||
// scanner .
|
||||
func scanner(wg *sync.WaitGroup, m mqtt.Client) {
|
||||
defer wg.Done()
|
||||
|
||||
srv := parser.Client()
|
||||
|
||||
ticker := time.NewTicker(180 * time.Second)
|
||||
defer ticker.Stop()
|
||||
|
||||
log.Println("Setup GMail message scanner...")
|
||||
for {
|
||||
select {
|
||||
|
||||
case <-ticker.C:
|
||||
log.Print("Updating messages...\n")
|
||||
msgs := []gMSG{}
|
||||
pageToken := ""
|
||||
for {
|
||||
req := srv.Users.Messages.List("me").LabelIds("UNREAD").Q("is:unread").Q("from:messaging@iamresponding.com")
|
||||
// req := srv.Users.Messages.List("me").Q("from:messaging@iamresponding.com")
|
||||
if pageToken != "" {
|
||||
req.PageToken(pageToken)
|
||||
}
|
||||
r, err := req.Do()
|
||||
if err != nil {
|
||||
log.Fatalf("Unable to retrieve messages: %v", err)
|
||||
}
|
||||
|
||||
log.Printf("Processing %v messages...\n", len(r.Messages))
|
||||
for _, m := range r.Messages {
|
||||
msg, err := srv.Users.Messages.Get("me", m.Id).Format("full").Do()
|
||||
if err != nil {
|
||||
log.Fatalf("Unable to retrieve message %v: %v", m.Id, err)
|
||||
}
|
||||
date := ""
|
||||
for _, h := range msg.Payload.Headers {
|
||||
if h.Name == "Date" {
|
||||
date = h.Value
|
||||
}
|
||||
// break
|
||||
}
|
||||
|
||||
msgs = append(msgs, gMSG{
|
||||
gmailID: msg.Id,
|
||||
date: date,
|
||||
snippet: html.UnescapeString(msg.Snippet),
|
||||
})
|
||||
}
|
||||
|
||||
if r.NextPageToken == "" {
|
||||
break
|
||||
}
|
||||
pageToken = r.NextPageToken
|
||||
}
|
||||
|
||||
msgs = reverse(msgs)
|
||||
|
||||
count, deleted := 0, 0
|
||||
for _, m := range msgs {
|
||||
count++
|
||||
|
||||
re := regexp.MustCompile(`^(?P<address>[^\s\[\[].*)\s\[\[(?P<city>[^\]\]].*)\]\]\s\((?P<type>[^\)].*)\)\s\-\s(?P<description>.*?)(?P<phone>\(\d{3}\)\s\d{3}\-\d{4})?\s?(?:F\d{9})?\s?(?:\d{7})?\s?(?P<time>\d{2}\:\d{2})?$`)
|
||||
if re.Match([]byte(m.snippet)) {
|
||||
|
||||
groups := re.SubexpNames()
|
||||
result := re.FindAllStringSubmatch(m.snippet, -1)
|
||||
|
||||
rt := map[string]string{}
|
||||
for i, n := range result[0] {
|
||||
rt[groups[i]] = n
|
||||
}
|
||||
// fmt.Printf("%v >> %+v\n", m.gmailID, rt)
|
||||
|
||||
_, err := srv.Users.Messages.Modify("me", m.gmailID, &gmail.ModifyMessageRequest{RemoveLabelIds: []string{"UNREAD"}}).Do()
|
||||
if err != nil {
|
||||
log.Fatalf("unable to modify message %v: %v", m.gmailID, err)
|
||||
}
|
||||
// log.Printf("Modified message %v.\n", msg)
|
||||
|
||||
var mutual_aid bool
|
||||
re := regexp.MustCompile(`^([\*]+).*$`)
|
||||
if re.Match([]byte(rt["address"])) {
|
||||
mutual_aid = true
|
||||
} else {
|
||||
mutual_aid = false
|
||||
}
|
||||
saveCallData(m.gmailID, rt["address"], rt["city"], rt["type"], rt["description"], rt["phone"], m.snippet, m.date, mutual_aid)
|
||||
} else {
|
||||
log.Printf("Couldn't parse a Gmail Message... (%s)\n", m.gmailID)
|
||||
_, err := srv.Users.Messages.Modify("me", m.gmailID, &gmail.ModifyMessageRequest{RemoveLabelIds: []string{"UNREAD"}, AddLabelIds: []string{"Label_2438996450476414779"}}).Do()
|
||||
if err != nil {
|
||||
log.Fatalf("unable to modify message %v: %v", m.gmailID, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
log.Printf("Done. %v messages processed, %v deleted\n", count, deleted)
|
||||
|
||||
case <-ctx.Done():
|
||||
log.Print("Caller has told us to stop\n")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func saveCallData(gid, iaddress, icity, itype, idescription, iphone, snippet, itime string, imutual_iad bool) error {
|
||||
_, err := conn.Exec(context.Background(), "INSERT INTO incidents(gmessage_id, address, city, type, description, phone, mutual_aid, snippet, time, created_on) VALUES($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)", gid, iaddress, icity, itype, idescription, iphone, imutual_iad, snippet, itime, time.Now())
|
||||
return err
|
||||
}
|
||||
|
||||
func toPrinter() {
|
||||
|
||||
fmt.Print("I'm in the Printer\n")
|
||||
var address, city, itype, description, phone, itime string
|
||||
// var mutual_aid bool
|
||||
// var created_on time.Time
|
||||
var err error
|
||||
// err = conn.QueryRow(context.Background(), "SELECT address, city, type, description, phone, time FROM incidents WHERE inc_id=$1", 566).Scan(&address, &city, &itype, &description, &phone, &itime)
|
||||
err = conn.QueryRow(context.Background(), "SELECT address, city, type, description, phone, time FROM incidents ORDER BY created_on DESC LIMIT 1").Scan(&address, &city, &itype, &description, &phone, &itime)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
prntr.Init()
|
||||
prntr.SetSmooth(1)
|
||||
prntr.SetFontSize(2, 3)
|
||||
prntr.SetFont("A")
|
||||
prntr.Formfeed()
|
||||
prntr.Write(" NEW PROVIDENCE FIRE DEPT")
|
||||
prntr.Formfeed()
|
||||
prntr.SetFont("B")
|
||||
prntr.Write(itime)
|
||||
prntr.Formfeed()
|
||||
if len(address) > 0 {
|
||||
prntr.Write("--- ADDRESS ------------------------------")
|
||||
prntr.SetFont("A")
|
||||
prntr.Write(string(address))
|
||||
prntr.Formfeed()
|
||||
} else {
|
||||
fmt.Print("There is no address value\n")
|
||||
}
|
||||
if len(city) > 0 {
|
||||
prntr.SetFont("B")
|
||||
prntr.Write("--- CITY ---------------------------------")
|
||||
prntr.SetFont("A")
|
||||
prntr.Write(string(city))
|
||||
prntr.Formfeed()
|
||||
} else {
|
||||
fmt.Print("There is no city value\n")
|
||||
}
|
||||
if len(itype) > 0 {
|
||||
prntr.SetFont("B")
|
||||
prntr.Write("--- TYPE ---------------------------------")
|
||||
prntr.SetFont("A")
|
||||
prntr.Write(string(itype))
|
||||
prntr.Formfeed()
|
||||
} else {
|
||||
fmt.Print("There is no type value\n")
|
||||
}
|
||||
if len(description) > 0 {
|
||||
prntr.SetFont("B")
|
||||
prntr.Write("--- DESCRIPTION --------------------------")
|
||||
prntr.SetFont("A")
|
||||
prntr.Write(string(description))
|
||||
prntr.Formfeed()
|
||||
} else {
|
||||
fmt.Print("There is no description value\n")
|
||||
}
|
||||
if len(phone) > 0 {
|
||||
prntr.SetFont("B")
|
||||
prntr.Write("--- PHONE --------------------------------")
|
||||
prntr.SetFont("A")
|
||||
prntr.Write(string(phone))
|
||||
prntr.Formfeed()
|
||||
} else {
|
||||
fmt.Print("There is no phone value\n")
|
||||
}
|
||||
// if value, ok := rt["time"]; ok {
|
||||
// prntr.Write("Time: " + value)
|
||||
// prntr.Formfeed()
|
||||
// } else {
|
||||
// fmt.Print("There is no time value\n")
|
||||
// }
|
||||
prntr.FormfeedN(3)
|
||||
// prntr.Cut()
|
||||
prntr.End()
|
||||
writerP.Flush()
|
||||
readWriter.Flush()
|
||||
log.Print("Printed message.\n")
|
||||
}
|
||||
|
||||
func main() {
|
||||
viper.SetConfigName("config") // name of config file (without extension)
|
||||
viper.SetConfigType("yml") // REQUIRED if the config file does not have the extension in the name
|
||||
// viper.AddConfigPath("/data/") //
|
||||
viper.AddConfigPath(".") // optionally look for config in the working directory
|
||||
|
||||
err := viper.ReadInConfig() // Find and read the config file
|
||||
if err != nil { // Handle errors reading the config file
|
||||
log.Fatalf("Fatal error config file: %s \n", err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// viper.WatchConfig()
|
||||
// viper.OnConfigChange(func(e fsnotify.Event) {
|
||||
// log.Println("Config file changed:", e.Name)
|
||||
// })
|
||||
|
||||
if err := viper.Unmarshal(&config); err != nil {
|
||||
log.Fatalf("Fatal error config file: %s \n", err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
logLevel, err := logrus.ParseLevel(viper.GetString("log.level"))
|
||||
if err != nil {
|
||||
logLevel = logrus.DebugLevel
|
||||
}
|
||||
|
||||
switch viper.GetString("log.level") {
|
||||
case "debug":
|
||||
log.SetLevel(logrus.DebugLevel)
|
||||
case "info":
|
||||
log.SetLevel(logrus.InfoLevel)
|
||||
case "warn":
|
||||
log.SetLevel(logrus.WarnLevel)
|
||||
case "error":
|
||||
log.SetLevel(logrus.ErrorLevel)
|
||||
default:
|
||||
log.SetLevel(logrus.DebugLevel)
|
||||
log.Warnf("Invalid log level supplied: '%s'", logLevel)
|
||||
}
|
||||
|
||||
customFormatter := new(logrus.TextFormatter)
|
||||
customFormatter.TimestampFormat = "2006-01-02 15:04:05"
|
||||
customFormatter.FullTimestamp = true
|
||||
log.SetFormatter(customFormatter)
|
||||
log.Printf("CONFIG: %+v", config)
|
||||
|
||||
// create a context that we can cancel
|
||||
var cancel context.CancelFunc
|
||||
ctx, cancel = context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
conn, err = pgx.Connect(context.Background(), fmt.Sprintf("postgres://%s:%s@%s:%d/%s", config.Postgres.Username, config.Postgres.Password, config.Postgres.Host, config.Postgres.Port, config.Postgres.Database))
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Unable to connect to database: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
log.Println("Setup PostgreSQL connection...")
|
||||
defer conn.Close(context.Background())
|
||||
|
||||
/// PRINTER START
|
||||
printerFile, err := os.OpenFile(config.Printer, os.O_RDWR, 0)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer printerFile.Close()
|
||||
|
||||
readerP = bufio.NewReader(printerFile)
|
||||
writerP = bufio.NewWriter(printerFile)
|
||||
readWriter = bufio.NewReadWriter(readerP, writerP)
|
||||
prntr = printer.New(readWriter)
|
||||
/// PRINTER END
|
||||
|
||||
// a WaitGroup for the goroutines to tell us they've stopped
|
||||
wg := sync.WaitGroup{}
|
||||
|
||||
mqttClient := mqttConnect(&wg)
|
||||
defer mqttClient.Disconnect(250)
|
||||
|
||||
// listen for C-c
|
||||
c := make(chan os.Signal, 1)
|
||||
signal.Notify(c, os.Interrupt)
|
||||
<-c
|
||||
log.Println("Main: received CTRL-c - shutting down")
|
||||
|
||||
// tell the goroutines to stop
|
||||
log.Println("Main: telling goroutines to stop")
|
||||
cancel()
|
||||
|
||||
// and wait for them both to reply back
|
||||
wg.Wait()
|
||||
log.Println("Main: all goroutines have told us they've finished")
|
||||
}
|
92
parser/client.go
Normal file
92
parser/client.go
Normal file
@ -0,0 +1,92 @@
|
||||
package parser
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
"golang.org/x/oauth2"
|
||||
"golang.org/x/oauth2/google"
|
||||
"google.golang.org/api/gmail/v1"
|
||||
)
|
||||
|
||||
// Client .
|
||||
func Client() *gmail.Service {
|
||||
b, err := ioutil.ReadFile("./credentials/credentials.json")
|
||||
if err != nil {
|
||||
log.Fatalf("Unable to read client secret file: %v", err)
|
||||
}
|
||||
|
||||
// If modifying these scopes, delete your previously saved token.json.
|
||||
config, err := google.ConfigFromJSON(b, gmail.GmailModifyScope)
|
||||
if err != nil {
|
||||
log.Fatalf("Unable to parse client secret file to config: %v", err)
|
||||
}
|
||||
client := getClient(config)
|
||||
|
||||
srv, err := gmail.New(client)
|
||||
if err != nil {
|
||||
log.Fatalf("Unable to retrieve Gmail client: %v", err)
|
||||
}
|
||||
return srv
|
||||
}
|
||||
|
||||
// Retrieve a token, saves the token, then returns the generated client.
|
||||
func getClient(config *oauth2.Config) *http.Client {
|
||||
// The file token.json stores the user's access and refresh tokens, and is
|
||||
// created automatically when the authorization flow completes for the first
|
||||
// time.
|
||||
tokFile := "./credentials/token.json"
|
||||
tok, err := tokenFromFile(tokFile)
|
||||
if err != nil {
|
||||
tok = getTokenFromWeb(config)
|
||||
saveToken(tokFile, tok)
|
||||
}
|
||||
return config.Client(context.Background(), tok)
|
||||
}
|
||||
|
||||
// Request a token from the web, then returns the retrieved token.
|
||||
func getTokenFromWeb(config *oauth2.Config) *oauth2.Token {
|
||||
authURL := config.AuthCodeURL("state-token", oauth2.AccessTypeOffline)
|
||||
fmt.Printf("Go to the following link in your browser then type the "+
|
||||
"authorization code: \n%v\n", authURL)
|
||||
|
||||
var authCode string
|
||||
if _, err := fmt.Scan(&authCode); err != nil {
|
||||
log.Fatalf("Unable to read authorization code: %v", err)
|
||||
}
|
||||
|
||||
tok, err := config.Exchange(context.TODO(), authCode)
|
||||
if err != nil {
|
||||
log.Fatalf("Unable to retrieve token from web: %v", err)
|
||||
}
|
||||
return tok
|
||||
}
|
||||
|
||||
// Retrieves a token from a local file.
|
||||
func tokenFromFile(file string) (*oauth2.Token, error) {
|
||||
f, err := os.Open(file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
tok := &oauth2.Token{}
|
||||
err = json.NewDecoder(f).Decode(tok)
|
||||
|
||||
return tok, err
|
||||
}
|
||||
|
||||
// Saves a token to a file path.
|
||||
func saveToken(path string, token *oauth2.Token) {
|
||||
fmt.Printf("Saving credential file to: %s\n", path)
|
||||
f, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
|
||||
if err != nil {
|
||||
log.Fatalf("Unable to cache oauth token: %v", err)
|
||||
}
|
||||
defer f.Close()
|
||||
json.NewEncoder(f).Encode(token)
|
||||
}
|
144
parser/message.go
Normal file
144
parser/message.go
Normal file
@ -0,0 +1,144 @@
|
||||
package parser
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"html"
|
||||
"log"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"google.golang.org/api/gmail/v1"
|
||||
)
|
||||
|
||||
// Message .
|
||||
type Message struct {
|
||||
gmailID string
|
||||
date string // retrieved from message header
|
||||
snippet string
|
||||
}
|
||||
|
||||
// GetMessages .
|
||||
func GetMessages(srv *gmail.Service) []Message {
|
||||
msgs := []Message{}
|
||||
pageToken := ""
|
||||
for {
|
||||
req := srv.Users.Messages.List("me").Q("is:unread").Q("from:messaging@iamresponding.com")
|
||||
// req := srv.Users.Messages.List("me").Q("is:unread")
|
||||
if pageToken != "" {
|
||||
req.PageToken(pageToken)
|
||||
}
|
||||
r, err := req.Do()
|
||||
if err != nil {
|
||||
log.Fatalf("Unable to retrieve messages: %v", err)
|
||||
}
|
||||
|
||||
log.Printf("Processing %v messages...\n", len(r.Messages))
|
||||
for _, m := range r.Messages {
|
||||
msg, err := srv.Users.Messages.Get("me", m.Id).Format("full").Do()
|
||||
if err != nil {
|
||||
log.Fatalf("Unable to retrieve message %v: %v", m.Id, err)
|
||||
}
|
||||
date := ""
|
||||
for _, h := range msg.Payload.Headers {
|
||||
if h.Name == "Date" {
|
||||
date = h.Value
|
||||
}
|
||||
// break
|
||||
}
|
||||
|
||||
msgs = append(msgs, Message{
|
||||
gmailID: msg.Id,
|
||||
date: date,
|
||||
snippet: html.UnescapeString(msg.Snippet),
|
||||
})
|
||||
}
|
||||
|
||||
if r.NextPageToken == "" {
|
||||
break
|
||||
}
|
||||
pageToken = r.NextPageToken
|
||||
}
|
||||
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
count, deleted := 0, 0
|
||||
for _, m := range msgs {
|
||||
count++
|
||||
|
||||
re := regexp.MustCompile(`^(?P<address>[^\s\[\[].*)\s\[\[(?P<city>[^\]\]].*)\]\]\s\((?P<type>[^\)].*)\)\s\-\s(?P<description>.*?)(?P<phone>\(\d{3}\)\s\d{3}\-\d{4})?\s?(?:F\d{9})?\s?(?:\d{7})?\s?(?P<time>\d{2}\:\d{2})?$`)
|
||||
if re.Match([]byte(m.snippet)) {
|
||||
|
||||
groups := re.SubexpNames()
|
||||
result := re.FindAllStringSubmatch(m.snippet, -1)
|
||||
|
||||
rt := map[string]string{}
|
||||
for i, n := range result[0] {
|
||||
rt[groups[i]] = n
|
||||
}
|
||||
|
||||
fmt.Printf("=============================================================\n")
|
||||
fmt.Printf("Message URL: https://mail.google.com/mail/u/0/#all/%v\n", m.gmailID)
|
||||
fmt.Printf("Snippet: %q\n", m.snippet)
|
||||
if value, ok := rt["address"]; ok {
|
||||
fmt.Printf("Address: %s\n", value)
|
||||
} else {
|
||||
fmt.Print("There is no address value\n")
|
||||
}
|
||||
if value, ok := rt["city"]; ok {
|
||||
fmt.Printf("City: %s\n", value)
|
||||
} else {
|
||||
fmt.Print("There is no city value\n")
|
||||
}
|
||||
if value, ok := rt["type"]; ok {
|
||||
fmt.Printf("Type: %s\n", value)
|
||||
} else {
|
||||
fmt.Print("There is no type value\n")
|
||||
}
|
||||
if value, ok := rt["description"]; ok {
|
||||
fmt.Printf("Description: %s\n", value)
|
||||
} else {
|
||||
fmt.Print("There is no description value\n")
|
||||
}
|
||||
if value, ok := rt["phone"]; ok {
|
||||
fmt.Printf("Phone: %s\n", value)
|
||||
} else {
|
||||
fmt.Print("There is no phone value\n")
|
||||
}
|
||||
if value, ok := rt["time"]; ok {
|
||||
fmt.Printf("Time: %s\n", value)
|
||||
} else {
|
||||
fmt.Print("There is no time value\n")
|
||||
}
|
||||
fmt.Printf("Date: %v\n", m.date)
|
||||
fmt.Printf("=============================================================\n")
|
||||
fmt.Printf("Options: (d)elete, (r)ead, (p)rint, (s)kip, (q)uit: [s] ")
|
||||
val := ""
|
||||
if _, err := reader.ReadString('\n'); err != nil {
|
||||
log.Fatalf("unable to scan input: %v", err)
|
||||
}
|
||||
val = strings.TrimSpace(val)
|
||||
switch val {
|
||||
case "d": // delete message
|
||||
if err := srv.Users.Messages.Delete("me", m.gmailID).Do(); err != nil {
|
||||
log.Fatalf("unable to delete message %v: %v", m.gmailID, err)
|
||||
}
|
||||
log.Printf("Deleted message %v.\n", m.gmailID)
|
||||
deleted++
|
||||
case "r": // mark as read
|
||||
msg, err := srv.Users.Messages.Modify("me", m.gmailID, &gmail.ModifyMessageRequest{RemoveLabelIds: []string{"UNREAD"}}).Do()
|
||||
if err != nil {
|
||||
log.Fatalf("unable to modify message %v: %v", m.gmailID, err)
|
||||
}
|
||||
log.Printf("Modified message %v.\n", msg)
|
||||
case "q": // quit
|
||||
log.Printf("Done. %v messages processed, %v deleted\n", count, deleted)
|
||||
os.Exit(0)
|
||||
default:
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return msgs
|
||||
}
|
594
printer/printer.go
Normal file
594
printer/printer.go
Normal file
@ -0,0 +1,594 @@
|
||||
package printer
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
// DLE ASCII (DataLinkEscape)
|
||||
DLE byte = 0x10
|
||||
|
||||
// EOT ASCII (EndOfTransmission)
|
||||
EOT byte = 0x04
|
||||
|
||||
// GS ASCII (Group Separator)
|
||||
GS byte = 0x1D
|
||||
)
|
||||
|
||||
// text replacement map
|
||||
var textReplaceMap = map[string]string{
|
||||
// horizontal tab
|
||||
"	": "\x09",
|
||||
"	": "\x09",
|
||||
|
||||
// linefeed
|
||||
" ": "\n",
|
||||
"
": "\n",
|
||||
|
||||
// xml stuff
|
||||
"'": "'",
|
||||
""": `"`,
|
||||
">": ">",
|
||||
"<": "<",
|
||||
|
||||
// ampersand must be last to avoid double decoding
|
||||
"&": "&",
|
||||
}
|
||||
|
||||
// replace text from the above map
|
||||
func textReplace(data string) string {
|
||||
for k, v := range textReplaceMap {
|
||||
data = strings.Replace(data, k, v, -1)
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
type Escpos struct {
|
||||
// destination
|
||||
dst io.ReadWriter
|
||||
|
||||
// font metrics
|
||||
width, height uint8
|
||||
|
||||
// state toggles ESC[char]
|
||||
underline uint8
|
||||
emphasize uint8
|
||||
upsidedown uint8
|
||||
rotate uint8
|
||||
|
||||
// state toggles GS[char]
|
||||
reverse, smooth uint8
|
||||
}
|
||||
|
||||
// reset toggles
|
||||
func (e *Escpos) reset() {
|
||||
e.width = 1
|
||||
e.height = 1
|
||||
|
||||
e.underline = 0
|
||||
e.emphasize = 0
|
||||
e.upsidedown = 0
|
||||
e.rotate = 0
|
||||
|
||||
e.reverse = 0
|
||||
e.smooth = 0
|
||||
}
|
||||
|
||||
// create Escpos printer
|
||||
func New(dst io.ReadWriter) (e *Escpos) {
|
||||
e = &Escpos{dst: dst}
|
||||
e.reset()
|
||||
return
|
||||
}
|
||||
|
||||
// write raw bytes to printer
|
||||
func (e *Escpos) WriteRaw(data []byte) (n int, err error) {
|
||||
if len(data) > 0 {
|
||||
log.Printf("Writing %d bytes\n", len(data))
|
||||
e.dst.Write(data)
|
||||
} else {
|
||||
log.Printf("Wrote NO bytes\n")
|
||||
}
|
||||
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// read raw bytes from printer
|
||||
func (e *Escpos) ReadRaw(data []byte) (n int, err error) {
|
||||
return e.dst.Read(data)
|
||||
}
|
||||
|
||||
// write a string to the printer
|
||||
func (e *Escpos) Write(data string) (int, error) {
|
||||
return e.WriteRaw([]byte(data))
|
||||
}
|
||||
|
||||
// init/reset printer settings
|
||||
func (e *Escpos) Init() {
|
||||
e.reset()
|
||||
e.Write("\x1B@")
|
||||
}
|
||||
|
||||
// end output
|
||||
func (e *Escpos) End() {
|
||||
e.Write("\xFA")
|
||||
}
|
||||
|
||||
// send cut
|
||||
func (e *Escpos) Cut() {
|
||||
e.Write("\x1DVA0")
|
||||
}
|
||||
|
||||
// send cut minus one point (partial cut)
|
||||
func (e *Escpos) CutPartial() {
|
||||
e.WriteRaw([]byte{GS, 0x56, 1})
|
||||
}
|
||||
|
||||
// send cash
|
||||
func (e *Escpos) Cash() {
|
||||
e.Write("\x1B\x70\x00\x0A\xFF")
|
||||
}
|
||||
|
||||
// send linefeed
|
||||
func (e *Escpos) Linefeed() {
|
||||
e.Write("\n")
|
||||
}
|
||||
|
||||
// send N formfeeds
|
||||
func (e *Escpos) FormfeedN(n int) {
|
||||
e.Write(fmt.Sprintf("\x1Bd%c", n))
|
||||
}
|
||||
|
||||
// send formfeed
|
||||
func (e *Escpos) Formfeed() {
|
||||
e.FormfeedN(1)
|
||||
}
|
||||
|
||||
// set font
|
||||
func (e *Escpos) SetFont(font string) {
|
||||
f := 0
|
||||
|
||||
switch font {
|
||||
case "A":
|
||||
f = 0
|
||||
case "B":
|
||||
f = 1
|
||||
case "C":
|
||||
f = 2
|
||||
default:
|
||||
log.Fatalf("Invalid font: '%s', defaulting to 'A'", font)
|
||||
f = 0
|
||||
}
|
||||
|
||||
e.Write(fmt.Sprintf("\x1BM%c", f))
|
||||
}
|
||||
|
||||
func (e *Escpos) SendFontSize() {
|
||||
e.Write(fmt.Sprintf("\x1D!%c", ((e.width-1)<<4)|(e.height-1)))
|
||||
}
|
||||
|
||||
// set font size
|
||||
func (e *Escpos) SetFontSize(width, height uint8) {
|
||||
if width > 0 && height > 0 && width <= 8 && height <= 8 {
|
||||
e.width = width
|
||||
e.height = height
|
||||
e.SendFontSize()
|
||||
} else {
|
||||
log.Fatalf("Invalid font size passed: %d x %d", width, height)
|
||||
}
|
||||
}
|
||||
|
||||
// send underline
|
||||
func (e *Escpos) SendUnderline() {
|
||||
e.Write(fmt.Sprintf("\x1B-%c", e.underline))
|
||||
}
|
||||
|
||||
// send emphasize / doublestrike
|
||||
func (e *Escpos) SendEmphasize() {
|
||||
e.Write(fmt.Sprintf("\x1BG%c", e.emphasize))
|
||||
}
|
||||
|
||||
// send upsidedown
|
||||
func (e *Escpos) SendUpsidedown() {
|
||||
e.Write(fmt.Sprintf("\x1B{%c", e.upsidedown))
|
||||
}
|
||||
|
||||
// send rotate
|
||||
func (e *Escpos) SendRotate() {
|
||||
e.Write(fmt.Sprintf("\x1BR%c", e.rotate))
|
||||
}
|
||||
|
||||
// send reverse
|
||||
func (e *Escpos) SendReverse() {
|
||||
e.Write(fmt.Sprintf("\x1DB%c", e.reverse))
|
||||
}
|
||||
|
||||
// send smooth
|
||||
func (e *Escpos) SendSmooth() {
|
||||
e.Write(fmt.Sprintf("\x1Db%c", e.smooth))
|
||||
}
|
||||
|
||||
// send move x
|
||||
func (e *Escpos) SendMoveX(x uint16) {
|
||||
e.Write(string([]byte{0x1b, 0x24, byte(x % 256), byte(x / 256)}))
|
||||
}
|
||||
|
||||
// send move y
|
||||
func (e *Escpos) SendMoveY(y uint16) {
|
||||
e.Write(string([]byte{0x1d, 0x24, byte(y % 256), byte(y / 256)}))
|
||||
}
|
||||
|
||||
// set underline
|
||||
func (e *Escpos) SetUnderline(v uint8) {
|
||||
e.underline = v
|
||||
e.SendUnderline()
|
||||
}
|
||||
|
||||
// set emphasize
|
||||
func (e *Escpos) SetEmphasize(u uint8) {
|
||||
e.emphasize = u
|
||||
e.SendEmphasize()
|
||||
}
|
||||
|
||||
// set upsidedown
|
||||
func (e *Escpos) SetUpsidedown(v uint8) {
|
||||
e.upsidedown = v
|
||||
e.SendUpsidedown()
|
||||
}
|
||||
|
||||
// set rotate
|
||||
func (e *Escpos) SetRotate(v uint8) {
|
||||
e.rotate = v
|
||||
e.SendRotate()
|
||||
}
|
||||
|
||||
// set reverse
|
||||
func (e *Escpos) SetReverse(v uint8) {
|
||||
e.reverse = v
|
||||
e.SendReverse()
|
||||
}
|
||||
|
||||
// set smooth
|
||||
func (e *Escpos) SetSmooth(v uint8) {
|
||||
e.smooth = v
|
||||
e.SendSmooth()
|
||||
}
|
||||
|
||||
// pulse (open the drawer)
|
||||
func (e *Escpos) Pulse() {
|
||||
// with t=2 -- meaning 2*2msec
|
||||
e.Write("\x1Bp\x02")
|
||||
}
|
||||
|
||||
// set alignment
|
||||
func (e *Escpos) SetAlign(align string) {
|
||||
a := 0
|
||||
switch align {
|
||||
case "left":
|
||||
a = 0
|
||||
case "center":
|
||||
a = 1
|
||||
case "right":
|
||||
a = 2
|
||||
default:
|
||||
log.Fatalf("Invalid alignment: %s", align)
|
||||
}
|
||||
e.Write(fmt.Sprintf("\x1Ba%c", a))
|
||||
}
|
||||
|
||||
// set language -- ESC R
|
||||
func (e *Escpos) SetLang(lang string) {
|
||||
l := 0
|
||||
|
||||
switch lang {
|
||||
case "en":
|
||||
l = 0
|
||||
case "fr":
|
||||
l = 1
|
||||
case "de":
|
||||
l = 2
|
||||
case "uk":
|
||||
l = 3
|
||||
case "da":
|
||||
l = 4
|
||||
case "sv":
|
||||
l = 5
|
||||
case "it":
|
||||
l = 6
|
||||
case "es":
|
||||
l = 7
|
||||
case "ja":
|
||||
l = 8
|
||||
case "no":
|
||||
l = 9
|
||||
default:
|
||||
log.Fatalf("Invalid language: %s", lang)
|
||||
}
|
||||
e.Write(fmt.Sprintf("\x1BR%c", l))
|
||||
}
|
||||
|
||||
// do a block of text
|
||||
func (e *Escpos) Text(params map[string]string, data string) {
|
||||
|
||||
// send alignment to printer
|
||||
if align, ok := params["align"]; ok {
|
||||
e.SetAlign(align)
|
||||
}
|
||||
|
||||
// set lang
|
||||
if lang, ok := params["lang"]; ok {
|
||||
e.SetLang(lang)
|
||||
}
|
||||
|
||||
// set smooth
|
||||
if smooth, ok := params["smooth"]; ok && (smooth == "true" || smooth == "1") {
|
||||
e.SetSmooth(1)
|
||||
}
|
||||
|
||||
// set emphasize
|
||||
if em, ok := params["em"]; ok && (em == "true" || em == "1") {
|
||||
e.SetEmphasize(1)
|
||||
}
|
||||
|
||||
// set underline
|
||||
if ul, ok := params["ul"]; ok && (ul == "true" || ul == "1") {
|
||||
e.SetUnderline(1)
|
||||
}
|
||||
|
||||
// set reverse
|
||||
if reverse, ok := params["reverse"]; ok && (reverse == "true" || reverse == "1") {
|
||||
e.SetReverse(1)
|
||||
}
|
||||
|
||||
// set rotate
|
||||
if rotate, ok := params["rotate"]; ok && (rotate == "true" || rotate == "1") {
|
||||
e.SetRotate(1)
|
||||
}
|
||||
|
||||
// set font
|
||||
if font, ok := params["font"]; ok {
|
||||
e.SetFont(strings.ToUpper(font[5:6]))
|
||||
}
|
||||
|
||||
// do dw (double font width)
|
||||
if dw, ok := params["dw"]; ok && (dw == "true" || dw == "1") {
|
||||
e.SetFontSize(2, e.height)
|
||||
}
|
||||
|
||||
// do dh (double font height)
|
||||
if dh, ok := params["dh"]; ok && (dh == "true" || dh == "1") {
|
||||
e.SetFontSize(e.width, 2)
|
||||
}
|
||||
|
||||
// do font width
|
||||
if width, ok := params["width"]; ok {
|
||||
if i, err := strconv.Atoi(width); err == nil {
|
||||
e.SetFontSize(uint8(i), e.height)
|
||||
} else {
|
||||
log.Fatalf("Invalid font width: %s", width)
|
||||
}
|
||||
}
|
||||
|
||||
// do font height
|
||||
if height, ok := params["height"]; ok {
|
||||
if i, err := strconv.Atoi(height); err == nil {
|
||||
e.SetFontSize(e.width, uint8(i))
|
||||
} else {
|
||||
log.Fatalf("Invalid font height: %s", height)
|
||||
}
|
||||
}
|
||||
|
||||
// do y positioning
|
||||
if x, ok := params["x"]; ok {
|
||||
if i, err := strconv.Atoi(x); err == nil {
|
||||
e.SendMoveX(uint16(i))
|
||||
} else {
|
||||
log.Fatalf("Invalid x param %s", x)
|
||||
}
|
||||
}
|
||||
|
||||
// do y positioning
|
||||
if y, ok := params["y"]; ok {
|
||||
if i, err := strconv.Atoi(y); err == nil {
|
||||
e.SendMoveY(uint16(i))
|
||||
} else {
|
||||
log.Fatalf("Invalid y param %s", y)
|
||||
}
|
||||
}
|
||||
|
||||
// do text replace, then write data
|
||||
data = textReplace(data)
|
||||
if len(data) > 0 {
|
||||
e.Write(data)
|
||||
}
|
||||
}
|
||||
|
||||
// feed the printer
|
||||
func (e *Escpos) Feed(params map[string]string) {
|
||||
// handle lines (form feed X lines)
|
||||
if l, ok := params["line"]; ok {
|
||||
if i, err := strconv.Atoi(l); err == nil {
|
||||
e.FormfeedN(i)
|
||||
} else {
|
||||
log.Fatalf("Invalid line number %s", l)
|
||||
}
|
||||
}
|
||||
|
||||
// handle units (dots)
|
||||
if u, ok := params["unit"]; ok {
|
||||
if i, err := strconv.Atoi(u); err == nil {
|
||||
e.SendMoveY(uint16(i))
|
||||
} else {
|
||||
log.Fatalf("Invalid unit number %s", u)
|
||||
}
|
||||
}
|
||||
|
||||
// send linefeed
|
||||
e.Linefeed()
|
||||
|
||||
// reset variables
|
||||
e.reset()
|
||||
|
||||
// reset printer
|
||||
e.SendEmphasize()
|
||||
e.SendRotate()
|
||||
e.SendSmooth()
|
||||
e.SendReverse()
|
||||
e.SendUnderline()
|
||||
e.SendUpsidedown()
|
||||
e.SendFontSize()
|
||||
e.SendUnderline()
|
||||
}
|
||||
|
||||
// feed and cut based on parameters
|
||||
func (e *Escpos) FeedAndCut(params map[string]string) {
|
||||
if t, ok := params["type"]; ok && t == "feed" {
|
||||
e.Formfeed()
|
||||
}
|
||||
|
||||
e.Cut()
|
||||
}
|
||||
|
||||
// Barcode sends a barcode to the printer.
|
||||
func (e *Escpos) Barcode(barcode string, format int) {
|
||||
code := ""
|
||||
switch format {
|
||||
case 0:
|
||||
code = "\x00"
|
||||
case 1:
|
||||
code = "\x01"
|
||||
case 2:
|
||||
code = "\x02"
|
||||
case 3:
|
||||
code = "\x03"
|
||||
case 4:
|
||||
code = "\x04"
|
||||
case 73:
|
||||
code = "\x49"
|
||||
}
|
||||
|
||||
// reset settings
|
||||
e.reset()
|
||||
|
||||
// set align
|
||||
e.SetAlign("center")
|
||||
|
||||
// write barcode
|
||||
if format > 69 {
|
||||
e.Write(fmt.Sprintf("\x1dk"+code+"%v%v", len(barcode), barcode))
|
||||
} else if format < 69 {
|
||||
e.Write(fmt.Sprintf("\x1dk"+code+"%v\x00", barcode))
|
||||
}
|
||||
e.Write(fmt.Sprintf("%v", barcode))
|
||||
}
|
||||
|
||||
// used to send graphics headers
|
||||
func (e *Escpos) gSend(m byte, fn byte, data []byte) {
|
||||
l := len(data) + 2
|
||||
|
||||
e.Write("\x1b(L")
|
||||
e.WriteRaw([]byte{byte(l % 256), byte(l / 256), m, fn})
|
||||
e.WriteRaw(data)
|
||||
}
|
||||
|
||||
// write an image
|
||||
func (e *Escpos) Image(params map[string]string, data string) {
|
||||
// send alignment to printer
|
||||
if align, ok := params["align"]; ok {
|
||||
e.SetAlign(align)
|
||||
}
|
||||
|
||||
// get width
|
||||
wstr, ok := params["width"]
|
||||
if !ok {
|
||||
log.Fatal("No width specified on image")
|
||||
}
|
||||
|
||||
// get height
|
||||
hstr, ok := params["height"]
|
||||
if !ok {
|
||||
log.Fatal("No height specified on image")
|
||||
}
|
||||
|
||||
// convert width
|
||||
width, err := strconv.Atoi(wstr)
|
||||
if err != nil {
|
||||
log.Fatalf("Invalid image width %s", wstr)
|
||||
}
|
||||
|
||||
// convert height
|
||||
height, err := strconv.Atoi(hstr)
|
||||
if err != nil {
|
||||
log.Fatalf("Invalid image height %s", hstr)
|
||||
}
|
||||
|
||||
// decode data frome b64 string
|
||||
dec, err := base64.StdEncoding.DecodeString(data)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.Printf("Image len:%d w: %d h: %d\n", len(dec), width, height)
|
||||
|
||||
// $imgHeader = self::dataHeader(array($img -> getWidth(), $img -> getHeight()), true);
|
||||
// $tone = '0';
|
||||
// $colors = '1';
|
||||
// $xm = (($size & self::IMG_DOUBLE_WIDTH) == self::IMG_DOUBLE_WIDTH) ? chr(2) : chr(1);
|
||||
// $ym = (($size & self::IMG_DOUBLE_HEIGHT) == self::IMG_DOUBLE_HEIGHT) ? chr(2) : chr(1);
|
||||
//
|
||||
// $header = $tone . $xm . $ym . $colors . $imgHeader;
|
||||
// $this -> graphicsSendData('0', 'p', $header . $img -> toRasterFormat());
|
||||
// $this -> graphicsSendData('0', '2');
|
||||
|
||||
header := []byte{
|
||||
byte('0'), 0x01, 0x01, byte('1'),
|
||||
}
|
||||
|
||||
a := append(header, dec...)
|
||||
|
||||
e.gSend(byte('0'), byte('p'), a)
|
||||
e.gSend(byte('0'), byte('2'), []byte{})
|
||||
|
||||
}
|
||||
|
||||
// write a "node" to the printer
|
||||
func (e *Escpos) WriteNode(name string, params map[string]string, data string) {
|
||||
cstr := ""
|
||||
if data != "" {
|
||||
str := data[:]
|
||||
if len(data) > 40 {
|
||||
str = fmt.Sprintf("%s ...", data[0:40])
|
||||
}
|
||||
cstr = fmt.Sprintf(" => '%s'", str)
|
||||
}
|
||||
log.Printf("Write: %s => %+v%s\n", name, params, cstr)
|
||||
|
||||
switch name {
|
||||
case "text":
|
||||
e.Text(params, data)
|
||||
case "feed":
|
||||
e.Feed(params)
|
||||
case "cut":
|
||||
e.FeedAndCut(params)
|
||||
case "pulse":
|
||||
e.Pulse()
|
||||
case "image":
|
||||
e.Image(params, data)
|
||||
}
|
||||
}
|
||||
|
||||
// ReadStatus Read the status n from the printer
|
||||
func (e *Escpos) ReadStatus(n byte) (byte, error) {
|
||||
e.WriteRaw([]byte{DLE, EOT, n})
|
||||
data := make([]byte, 1)
|
||||
_, err := e.ReadRaw(data)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return data[0], nil
|
||||
}
|
Reference in New Issue
Block a user