(cont.)
Just to give some context on some of the components around the code structure.. I wrote this up around an earlier version of aggregate code. This generic bit simplifies things by removing the need of the Crud functions for each aggregate.
Domain ObjectsA domain object can be used as an aggregate by adding the event.AggregateRoot struct and finish implementing event.Aggregate. The AggregateRoot implements logic for adding events after they are either Raised by a command or Appended by the eventstore Load or service ApplyFn methods. It also tracks the uncommitted events that are saved using the eventstore Save method.
type User struct {
Identity string ```json:"identity"`
CreatedAt time.Time
event.AggregateRoot
}
// StreamID for the aggregate when stored or loaded from ES.
func (a *User) StreamID() string {
return "user-" + a.Identity
}
// ApplyEvent to the aggregate state.
func (a *User) ApplyEvent(lis ...event.Event) {
for _, e := range lis {
switch e := e.(type) {
case *UserCreated:
a.Identity = e.Identity
a.CreatedAt = e.EventMeta().CreatedDate
/* ... */
}
}
}
Events
Events are applied to the aggregate. They are defined by adding the event.Meta and implementing the getter/setters for event.Event
type UserCreated struct {
eventMeta event.Meta
Identity string
}
func (c *UserCreated) EventMeta() (m event.Meta) {
if c != nil {
m = c.eventMeta
}
return m
}
func (c *UserCreated) SetEventMeta(m event.Meta) {
if c != nil {
c.eventMeta = m
}
}
Reading Events from EventStore
With a domain object that implements the event.Aggregate the event store client can load events and apply them using the Load(ctx, agg) method.
// GetUser populates an user from event store.
func (rw *User) GetUser(ctx context.Context, userID string) (*domain.User, error) {
user := &domain.User{Identity: userID}
err := rw.es.Load(ctx, user)
if err != nil {
if err != nil {
if errors.Is(err, eventstore.ErrStreamNotFound) {
return user, ErrNotFound
}
return user, err
}
return nil, err
}
return user, err
}
OnX Commands
An OnX command will validate the state of the domain object can have the command performed on it. If it can be applied it raises the event using event.Raise() Otherwise it returns an error.
// OnCreate raises an UserCreated event to create the user.
// Note: The handler will check that the user does not already exsist.
func (a *User) OnCreate(identity string) error {
event.Raise(a, &UserCreated{Identity: identity})
return nil
}
// OnScored will attempt to score a task.
// If the task is not in a Created state it will fail.
func (a *Task) OnScored(taskID string, score int64, attributes Attributes) error {
if a.State != TaskStateCreated {
return fmt.Errorf("task expected created, got %s", a.State)
}
event.Raise(a, &TaskScored{TaskID: taskID, Attributes: attributes, Score: score})
return nil
}
Crud Operations for OnX Commands
The following functions in the aggregate service can be used to perform creation and updating of aggregates. The Update function will ensure the aggregate exists, where the Create is intended for non-existent aggregates. These can probably be combined into one function.
// Create is used when the stream does not yet exist.
func (rw *User) Create(
ctx context.Context,
identity string,
fn func(*domain.User) error,
) (*domain.User, error) {
session, err := rw.GetUser(ctx, identity)
if err != nil && !errors.Is(err, ErrNotFound) {
return nil, err
}
if err = fn(session); err != nil {
return nil, err
}
_, err = rw.es.Save(ctx, session)
return session, err
}
// Update is used when the stream already exists.
func (rw *User) Update(
ctx context.Context,
identity string,
fn func(*domain.User) error,
) (*domain.User, error) {
session, err := rw.GetUser(ctx, identity)
if err != nil {
return nil, err
}
if err = fn(session); err != nil {
return nil, err
}
_, err = rw.es.Save(ctx, session)
return session, err
}
PEP 691: JSON-based Simple API for Python Package Indexes
The “Simple Repository API” that was defined in PEP 503 (and was in use much longer than that) has served us reasonably well for a very long time. However, the reliance on using HTML as the data exchange mechanism has several shortcomings. ⌘ Read more
Webassembly running go code in the browser
Learning to build a Beautifier JSON online service in Go and make it run in the browser with Webassembly 1 points posted by IVAN CORRALES SOLERA ⌘ Read more
zerolog - Zero Allocation JSON Logger
1 points posted by Everton Marques ⌘ Read more
#!/bin/sh
# Validate environment
if ! command -v msgbus > /dev/null; then
printf "missing msgbus command. Use: go install git.mills.io/prologic/msgbus/cmd/msgbus@latest"
exit 1
fi
if ! command -v salty > /dev/null; then
printf "missing salty command. Use: go install go.mills.io/salty/cmd/salty@latest"
exit 1
fi
if ! command -v salty-keygen > /dev/null; then
printf "missing salty-keygen command. Use: go install go.mills.io/salty/cmd/salty-keygen@latest"
exit 1
fi
if [ -z "$SALTY_IDENTITY" ]; then
export SALTY_IDENTITY="$HOME/.config/salty/$USER.key"
fi
get_user () {
user=$(grep user: "$SALTY_IDENTITY" | awk '{print $3}')
if [ -z "$user" ]; then
user="$USER"
fi
echo "$user"
}
stream () {
if [ -z "$SALTY_IDENTITY" ]; then
echo "SALTY_IDENTITY not set"
exit 2
fi
jq -r '.payload' | base64 -d | salty -i "$SALTY_IDENTITY" -d
}
lookup () {
if [ $# -lt 1 ]; then
printf "Usage: %s nick@domain\n" "$(basename "$0")"
exit 1
fi
user="$1"
nick="$(echo "$user" | awk -F@ '{ print $1 }')"
domain="$(echo "$user" | awk -F@ '{ print $2 }')"
curl -qsSL "https://$domain/.well-known/salty/${nick}.json"
}
readmsgs () {
topic="$1"
if [ -z "$topic" ]; then
topic=$(get_user)
fi
export SALTY_IDENTITY="$HOME/.config/salty/$topic.key"
if [ ! -f "$SALTY_IDENTITY" ]; then
echo "identity file missing for user $topic" >&2
exit 1
fi
msgbus sub "$topic" "$0"
}
sendmsg () {
if [ $# -lt 2 ]; then
printf "Usage: %s nick@domain.tld <message>\n" "$(basename "$0")"
exit 0
fi
if [ -z "$SALTY_IDENTITY" ]; then
echo "SALTY_IDENTITY not set"
exit 2
fi
user="$1"
message="$2"
salty_json="$(mktemp /tmp/salty.XXXXXX)"
lookup "$user" > "$salty_json"
endpoint="$(jq -r '.endpoint' < "$salty_json")"
topic="$(jq -r '.topic' < "$salty_json")"
key="$(jq -r '.key' < "$salty_json")"
rm "$salty_json"
message="[$(date +%FT%TZ)] <$(get_user)> $message"
echo "$message" \
| salty -i "$SALTY_IDENTITY" -r "$key" \
| msgbus -u "$endpoint" pub "$topic"
}
make_user () {
mkdir -p "$HOME/.config/salty"
if [ $# -lt 1 ]; then
user=$USER
else
user=$1
fi
identity_file="$HOME/.config/salty/$user.key"
if [ -f "$identity_file" ]; then
printf "user key exists!"
exit 1
fi
# Check for msgbus env.. probably can make it fallback to looking for a config file?
if [ -z "$MSGBUS_URI" ]; then
printf "missing MSGBUS_URI in environment"
exit 1
fi
salty-keygen -o "$identity_file"
echo "# user: $user" >> "$identity_file"
pubkey=$(grep key: "$identity_file" | awk '{print $4}')
cat <<- EOF
Create this file in your webserver well-known folder. https://hostname.tld/.well-known/salty/$user.json
{
"endpoint": "$MSGBUS_URI",
"topic": "$user",
"key": "$pubkey"
}
EOF
}
# check if streaming
if [ ! -t 1 ]; then
stream
exit 0
fi
# Show Help
if [ $# -lt 1 ]; then
printf "Commands: send read lookup"
exit 0
fi
CMD=$1
shift
case $CMD in
send)
sendmsg "$@"
;;
read)
readmsgs "$@"
;;
lookup)
lookup "$@"
;;
make-user)
make_user "$@"
;;
esac
Ignite Realtime Blog: REST API Openfire plugin 1.7.1 released!
Moments ago, we’ve released version 1.7.1 of the Openfire REST API plugin. This version fixes changes to the API (notably the JSON representation of some entities) that inadvertently sneaked into the 1.7.0 release. The API in 1.7.0 should closely resemble that of releases prior to 1.7.0!
The updated plugin should become available for download in your Openfire admin console in the course of the next few hours. Alternative … ⌘ Read more
QUT-Digital-Observatory/tidy_tweet
Tidies Twitter json collected with Twarc into relational tables.
Language: Python
Star: 1
Watch: 1 ⌘ Read more
oliviersm199/Tweet-Generator
The Tweet Generator uses a Markov chain to generate random tweet based off of past tweets. It uses Python and the Twitter API to obtain the last 200 tweets from a particular user, organizes them into a JSON tree structure and then executes a random walk on that tree structure. This results in sometimes hilarious sometimes nonsense tweets that mimic the Twitter user’s past tweets.
Language: Py … ⌘ Read more
Goland 使用教程 01:高效的处理 json 文本
大家好,我是渔夫子。
工欲善其事,必先利其器。今天我们讲解 Goland 是如何高效的处理 json 的。
01 将 json 直接转换成结构体首先我们有一个段 json 格式的数据如下,看下 Goland 是如何快捷的转换成结构体的。
”`
{
</span><span class="nl">"email"</span><span class="p">:</span><span class="w"> </span><span class="s2">"noah.poulsen@example.com"</sp ... ⌘ [Read more](https://gocn.vip/topics/20923)```
GoCN 每日新闻 (2021-12-28)
GoCN 每日新闻 (2021-12-28)
- 使用 Go SDK 与 OCI 对象存储交互https://lucasjellema.medium.com/interacting-with-oci-object-storage-using-go-sdk-first-steps-f50682418488
- 深入理解 Go Json.Unmarshal 精度丢失之谜https://mp.weixin.qq.com/s/36CqC1U54LUd4-izt4iZ1g
- 基于 OpenTelemetry 和 ClickHouse 的分布式链路 … ⌘ Read more
[WIP] Query any data source using SQL, building Presto or AWS Athena alternative
xyr is a very lightweight, simple, and powerful data ETL platform that helps you to query available data sources using SQL.
- Simple Presto Alternative.
- Simple AWS Athena Alternative.
- Convert your JSON documents into a SQL DB.
- Query your CSV files easily and join them with other data.
internaly
xyrutilizesSQLiteas an embeded sql datastore (it may be changed in future and we c … ⌘ Read more
https://github.com/kellyjonbrazil/jtbl json output
https://dgl.cx/2020/06/sqlite-json-support sqlite sqlite
I agree clients should present things better (part of why I’m writing one!). But that should be additive. There’s a reason we’re not passing json around.
Re-txt: convert from JSON/YAML/toml/CSV to YAML/JSON/toml ⌘ Read more…
a2a - json/yaml, toml/json, hcl/json, csv/json and vs converter! ⌘ Read more…
Building a high performance JSON parser #json ⌘ https://dave.cheney.net/high-performance-json.html
NJson Package Unmarshal/Decode nested JSON by JSON Path ⌘ https://github.com/m7shapan/njson
Optional json fields in go ⌘ https://eli.thegreenplace.net/2020/optional-json-fields-in-go
Golang how to unmarshal a subset of nested JSON data ⌘ https://dev.to/m7shapan/golang-how-to-unmarshal-a-subset-of-nested-json-data-d84
Use dhall for package.json #idea
When all fails, rm ./package-lock.json and try again
json2tsv: a JSON to TSV converter: https://www.codemadness.org/json2tsv.html
Convert iota List to String in JSON ⌘ Read more…
JSON Web Tokens: Authenticating your API ⌘ Read more…
JSON Encode - Pretty Print ⌘ Read more…
JSON as configuration files: please don’t https://arp242.net/weblog/json_as_configuration_files-_please_dont
And an example configuration file: https://files.mdosch.de/2018-03/config.json.example
GitHub - automerge/automerge: A JSON-like data structure that can be modified concurrently by diff… https://github.com/automerge/automerge
JSON Decode into Objects ⌘ Read more…
JSON Encode an Array of Objects ⌘ Read more…
Manu Sporny über JSON-LD ?~L~X https://notiz.blog/b/1yt
Embedded JSON(-LD) ?~L~X https://notiz.blog/b/1YA