feat(gateway): handle guild petition turn-in at the gateway - #58
Conversation
There was a problem hiding this comment.
Pull request overview
Implements the gateway-driven guild petition turn-in flow for WotLK guild creation: the gateway validates a petition via a new worldserver gRPC endpoint, creates the guild via the guild service, and propagates membership linking via a new guild.created NATS event consumed by worldservers and gateways.
Changes:
- Add
CanTurnInGuildPetitiongRPC endpoint (proto + Go/C++ libsidecar server/client plumbing) and gateway handler forCMSG_TURN_IN_PETITION. - Add
CreateGuildRPC to the guild service + MySQL implementation, plus publish/consume the newguild.createdevent. - Wire
guild.createdconsumption to update online sessions/worldserver state; add tests for guild creation and gateway petition turn-in.
Reviewed changes
Copilot reviewed 51 out of 53 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| shared/events/producer-guild.go | Adds GuildCreated producer API for NATS publishing. |
| shared/events/mocks/GuildServiceProducer.go | Updates mock to support GuildCreated. |
| shared/events/events-guild.go | Defines guild.created subject and payload type. |
| gen/worldserver/pb/worldserver.pb.go | Generated protobuf updates for CanTurnInGuildPetition messages/enums. |
| gen/worldserver/pb/worldserver_grpc.pb.go | Generated gRPC stubs for CanTurnInGuildPetition. |
| gen/worldserver/pb/mocks/WorldServerServiceClient.go | Updates mock client with CanTurnInGuildPetition. |
| gen/guilds/pb/guilds.pb.go | Generated protobuf updates for CreateGuild params/response. |
| gen/guilds/pb/guilds_grpc.pb.go | Generated gRPC stubs for CreateGuild. |
| game-server/libsidecar/petition-api.h | New C ABI for petition validation handler binding. |
| game-server/libsidecar/petition-api.go | cgo bridge for petition validation handler + data conversion/freeing. |
| game-server/libsidecar/petition-api.c | C shim storing and invoking petition validation handler. |
| game-server/libsidecar/grpcapi/server-petitions.go | Implements gRPC CanTurnInGuildPetition server handler (Go libsidecar). |
| game-server/libsidecar/grpcapi/petition-errors.go | Defines ErrNoPetitionHandler. |
| game-server/libsidecar/grpcapi/cpp-bindings.go | Adds Go-side bindings/types for petition validation results. |
| game-server/libsidecar/grpc-api.go | Registers petition handler in Go libsidecar GRPC setup. |
| game-server/libsidecar/events-guilds.go | Adds Go-side guild.created hook binding + handler implementation. |
| game-server/libsidecar/events-guild.h | Adds C hook signature for guild.created. |
| game-server/libsidecar/events-guild.c | Implements hook registration/call for guild.created. |
| game-server/libsidecar/consumer/handlers-fabric.go | Extends handler factory interface with GuildCreatedHandler. |
| game-server/libsidecar/consumer/consumer.go | Subscribes to guild.created and dispatches to handler queue (Go). |
| game-server/libsidecar-cpp/src/nats/handlers.h | Declares C++ handler factory for guild.created. |
| game-server/libsidecar-cpp/src/nats/handlers.cpp | Parses guild.created payload and dispatches hook (C++). |
| game-server/libsidecar-cpp/src/nats/consumer.cpp | Subscribes/routes guild.created in the C++ consumer. |
| game-server/libsidecar-cpp/src/grpc/worldserver_service.h | Adds C++ gRPC service method + binding pointer for petition validation. |
| game-server/libsidecar-cpp/src/grpc/worldserver_service.cpp | Implements CanTurnInGuildPetition server method (C++). |
| game-server/libsidecar-cpp/src/events/event_hooks.h | Adds registration/dispatch for guild.created hook (C++). |
| game-server/libsidecar-cpp/src/events/event_hooks.cpp | Implements registration/dispatch for guild.created hook (C++). |
| game-server/libsidecar-cpp/src/api.cpp | Exposes C API for petition handler + guild.created hook registration (C++). |
| game-server/libsidecar-cpp/include/petition-api.h | Public C header for petition handler (C++ libsidecar). |
| game-server/libsidecar-cpp/include/libsidecar/tc9_types.h | Adds petition validation types to exported ABI. |
| game-server/libsidecar-cpp/include/libsidecar/tc9_events.h | Adds TC9EventGuildCreated event + hook type. |
| game-server/libsidecar-cpp/include/libsidecar.h | Exposes new petition API + guild.created hook entrypoints. |
| game-server/libsidecar-cpp/include/events-guild.h | Adds guild.created hook declaration in public header. |
| apps/guildserver/service/guilds.go | Adds CreateGuild service method + publishes guild.created event. |
| apps/guildserver/service/guilds-create_test.go | Adds unit tests for CreateGuild behavior and event payload. |
| apps/guildserver/service/guilds-cache.go | Extends cache interface with source-of-truth membership lookup. |
| apps/guildserver/service/guilds-cache_inmem.go | Implements membership source recheck + CreateGuild cache hydration. |
| apps/guildserver/service/guilds-cache_inmem_test.go | Adds tests for source recheck eviction and leader-online marking. |
| apps/guildserver/server/guilds.go | Adds gRPC CreateGuild handler with status-code mapping. |
| apps/guildserver/server/guilds-logger_debug.go | Adds debug logging wrapper for CreateGuild. |
| apps/guildserver/repo/mocks/guilds-repo.go | Extends repo mock with CreateGuild. |
| apps/guildserver/repo/guilds.go | Adds CreateGuild repo API + ErrGuildNameTaken. |
| apps/guildserver/repo/guilds_mysql.go | Implements GuildByRealmAndID + transactional CreateGuild (MySQL). |
| apps/gateway/session/petition.go | Adds CMSG_TURN_IN_PETITION handling via gRPC validate + guild create. |
| apps/gateway/session/petition_test.go | Adds tests for petition turn-in success/fallback/error mappings. |
| apps/gateway/session/handler.go | Routes CMsgTurnInPetition to the new handler. |
| apps/gateway/session/handler-events.go | Registers session handler for EventTypeGuildCreated. |
| apps/gateway/session/guild.go | Adds guild command/result sender + handles GuildCreated event to link sessions. |
| apps/gateway/service/listener-guild.go | Subscribes to guild.created and broadcasts to sessions. |
| apps/gateway/events-broadcaster/mocks/Broadcaster.go | Adds broadcaster mock method for NewGuildCreatedEvent. |
| apps/gateway/events-broadcaster/broadcaster.go | Adds EventTypeGuildCreated broadcasting to leader + signatories. |
| api/proto/v1/worldserver/worldserver.proto | Adds CanTurnInGuildPetition RPC and messages. |
| api/proto/v1/guilds/guilds.proto | Adds CreateGuild RPC and messages. |
Files not reviewed (2)
- apps/gateway/events-broadcaster/mocks/Broadcaster.go: Generated file
- apps/guildserver/repo/mocks/guilds-repo.go: Generated file
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if resp.err != nil { | ||
| return nil, resp.err | ||
| } |
There was a problem hiding this comment.
Fixed: the Go libsidecar now maps the unbound-handler error to gRPC Unimplemented so the gateway fallback triggers (the native C++ implementation already returned Unimplemented).
50dcee1 to
1bcd640
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.
The gateway intercepts CMSG_TURN_IN_PETITION, asks the player's worldserver to validate the petition over gRPC (charter item, ownership, signatures), then creates the guild through the guild service with the signatories as members. Arena charters are forwarded to the worldserver untouched. The guild service maps business failures of CreateGuild to gRPC status codes so the gateway can render the proper client errors (name taken, already in guild, invalid name) without matching error strings. Sessions of online signatories are linked to the new guild through the guild.created event.
If the worldserver doesn't implement CanTurnInGuildPetition yet (mixed versions in the cluster), the turn-in was silently dropped: the gRPC call failed and the client never got an answer nor the packet. Fall back to the in-process turn-in flow on Unimplemented.
1bcd640 to
6d7a279
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. |
This is the trigger part of the guild-creation rework we discussed on Discord: the gateway intercepts CMSG_TURN_IN_PETITION, asks the player's worldserver to validate the petition over gRPC (charter item, ownership, signatures — validation and MinPetitionSigns stay world-side), then creates the guild through the guild service with the signatories as members and answers SMSG_TURN_IN_PETITION_RESULTS. Arena charters are forwarded to the worldserver untouched, and if the worldserver doesn't implement the validation endpoint yet (mixed versions) the turn-in falls back to the in-process flow instead of being dropped.
The guild service maps CreateGuild business failures to gRPC status codes so the gateway renders the proper client errors (name taken, already in a guild, invalid name) without matching error strings. Sessions of online signatories are linked to the new guild through the guild.created event.
Stacked on #55 and #57: the net-new commits are the last two, the diff collapses once those merge. The AC-side counterpart (validation handler + guild.created consumer) walkline/azerothcore-wotlk#6.