feat(libsidecar): worldserver petition validation endpoint + guild.created hook - #57
feat(libsidecar): worldserver petition validation endpoint + guild.created hook#573kynox wants to merge 6 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
Adds end-to-end “create guild” support across the guildserver (RPC + repo + cache + events) and exposes it to the native libsidecar-cpp so the worldserver can route guild creation through the guild service in cluster mode.
Changes:
- Introduces
CreateGuildgRPC RPC (+ generated Go bindings) and corresponding server/service implementations. - Adds a
guild.createdNATS event (producer interface + payload + mock) emitted on guild creation. - Adds
libsidecar-cppguild service client wiring and exportsTC9GuildCreate, plus config/env plumbing and tests for creation + cache behavior.
Reviewed changes
Copilot reviewed 19 out of 23 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| shared/events/producer-guild.go | Extends guild event producer API with GuildCreated publisher. |
| shared/events/mocks/GuildServiceProducer.go | Updates mock to include GuildCreated. |
| shared/events/events-guild.go | Adds GuildEventGuildCreated subject mapping and payload struct. |
| gen/guilds/pb/guilds.pb.go | Regenerates Go protobuf types to include CreateGuild* messages. |
| gen/guilds/pb/guilds_grpc.pb.go | Regenerates Go gRPC bindings to include CreateGuild RPC. |
| api/proto/v1/guilds/guilds.proto | Defines CreateGuild RPC and request/response messages. |
| apps/guildserver/server/guilds.go | Implements gRPC handler for CreateGuild. |
| apps/guildserver/server/guilds-logger_debug.go | Adds debug logging middleware for CreateGuild. |
| apps/guildserver/service/guilds.go | Implements guild creation flow + validation + event emission. |
| apps/guildserver/service/guilds-cache.go | Adds GuildMembershipSource to support bypassing stale cached membership. |
| apps/guildserver/service/guilds-cache_inmem.go | Implements cache eviction-from-source and cache hydration on CreateGuild. |
| apps/guildserver/service/guilds-create_test.go | Adds tests for service-level guild creation behavior. |
| apps/guildserver/service/guilds-cache_inmem_test.go | Adds tests for source-membership eviction + leader-online caching on create. |
| apps/guildserver/repo/guilds.go | Adds ErrGuildNameTaken and CreateGuild repo interface method. |
| apps/guildserver/repo/mocks/guilds-repo.go | Adds repo mock method for CreateGuild. |
| apps/guildserver/repo/guilds_mysql.go | Implements GuildByRealmAndID, CreateGuild, and improves no-rows handling. |
| game-server/libsidecar-cpp/src/grpc/clients.h | Adds guild stub/channel and CreateGuild client method + Connect param. |
| game-server/libsidecar-cpp/src/grpc/clients.cpp | Wires guild channel/stub and implements GrpcClients::CreateGuild. |
| game-server/libsidecar-cpp/src/core/config.h | Adds guild_service_address config getter/member. |
| game-server/libsidecar-cpp/src/core/config.cpp | Loads TC9_GUILD_SERVICE_ADDRESS env var. |
| game-server/libsidecar-cpp/src/api.cpp | Stores realm id on init; exports TC9GuildCreate wrapper. |
| game-server/libsidecar-cpp/include/libsidecar.h | Declares TC9GuildCreate C API with usage contract. |
| game-server/libsidecar-cpp/CMakeLists.txt | Adds guilds.proto to generated proto set. |
Files not reviewed (4)
- apps/guildserver/repo/mocks/guilds-repo.go: Generated file
- gen/guilds/pb/guilds.pb.go: Generated file
- gen/guilds/pb/guilds_grpc.pb.go: Generated file
- shared/events/mocks/GuildServiceProducer.go: Generated file
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| guild, err := g.r.GuildByRealmAndID(ctx, realmID, id) | ||
| if err != nil { | ||
| return id, fmt.Errorf("guild %d created but not cached, err: %w", id, err) | ||
| } | ||
|
|
||
| g.cacheMutex.Lock() | ||
| g.cache[realmID][id] = guild | ||
| for _, member := range guild.GuildMembers { | ||
| if member.PlayerGUID == leaderGUID { | ||
| // Guild creation is always driven by a live session of the leader, | ||
| // but the world may not have flushed the online flag to the | ||
| // characters table yet, so the hydration can miss it. | ||
| member.Status = repo.GuildMemberStatusOnline | ||
| } | ||
| g.guildMembersCache[realmID][member.PlayerGUID] = member | ||
| } | ||
| g.cacheMutex.Unlock() |
There was a problem hiding this comment.
Added an init guard for the per-realm inner maps before the cache writes.
e9eafea to
070ce26
Compare
|
Force-pushed a full rework: the CreateGuild client export is gone, replaced by the worldserver validation endpoint and the guild.created hook (both Go and native implementations). Details in the updated description. |
c926147 to
10c879e
Compare
Adds a CreateGuild RPC: the guild row, the five default 3.3.5 ranks and the
leader as guild master are inserted in one transaction, the guild id being
allocated as MAX(guildid)+1 with a retry on primary key conflicts (a
worldserver can still create guilds in-process concurrently). The created
guild is cached hydrated and a guild.created event is published.
Also implements the GuildByRealmAndID mysql repo method that was left as
panic("implement me") - the cache needs it to hydrate the new guild.
(cherry picked from commit 3608d5a3f14348c31ca54faafb07f27948919bfc)
…ild creation The world can disband guilds without going through the guild service (e.g. GM .guild delete handled in-process), leaving a stale positive membership in the in-memory cache. CreateGuild now rechecks a positive answer against the database and evicts the stale cache entry, instead of rejecting with 'already in guild' until the service restarts. Also treats a missing guild_member row as 'not in a guild' in the MySQL repo instead of surfacing sql.ErrNoRows. (cherry picked from commit 2c779169db1722cb20bfa58faf8674a482af09f1)
Guild creation is always driven by a live session of the leader, but in cluster mode the world doesn't flush the online flag to the characters table, so the hydration read the leader back as offline. This left the fresh guild with an empty online-members list: the roster showed the leader disconnected and guild events (e.g. MOTD updates) were broadcast to nobody until the leader relogged. (cherry picked from commit 7000ccaa6c9f19ce89c1f3884f355243a74628d9)
…ity) The core's CreateDefaultGuildRanks gives both Guild Master and Officer GR_RIGHT_ALL; the service only gave the Officer chat rights, so a freshly promoted officer had every guild action greyed out client-side (invite, promote, etc.). Match the core layout and assert it in the create test.
- CreateGuildParams gains signatoryGUIDs; members are inserted with the lowest rank in the same transaction, skipping characters that joined another guild since signing. - guild.created event now carries the added member guids so worldservers can populate the state for the new guild. - New worldserver RPC CanTurnInGuildPetition for the gateway to validate petitions on the worldserver side before calling CreateGuild.
…eated hook Both implementations (Go and native C++) gain: - CanTurnInGuildPetition gRPC method dispatched on the world update thread through a new TC9SetCanTurnInGuildPetitionHandler binding; - a guild.created NATS consumer that calls the new TC9SetOnGuildCreatedHook so worldservers can populate state for guilds created by the guild service.
10c879e to
22f4f21
Compare
|
Superseded by #81, which regroups the guild creation work into a single PR as discussed. Same content, rebased on current master, with the review points from this PR already applied. |
Reworked per our Discord discussion — this is now the worldserver plumbing for gateway-triggered guild creation instead of a CreateGuild client. Both libsidecar implementations (Go and native C++) gain:
CanTurnInGuildPetitiongRPC method on the worldserver service, dispatched on the world update thread through a newTC9SetCanTurnInGuildPetitionHandlerbinding, so petition validation (charter item, ownership, signatures) stays world-side;guild.createdNATS consumer wired to a newTC9SetOnGuildCreatedHook, so worldservers can populate state for guilds created by the guild service.Stacked on #55 (proto + RPC it builds on): the net-new commit is the last one. The gateway trigger is #58, the AC-side consumer/handler is the replacement of walkline/azerothcore-wotlk#5.