Skip to content

Commit

Permalink
feat: new go template (#25)
Browse files Browse the repository at this point in the history
  • Loading branch information
anandsunderraman authored Oct 4, 2021
1 parent 016e7ca commit cfdc109
Show file tree
Hide file tree
Showing 66 changed files with 19,250 additions and 1,635 deletions.
4 changes: 4 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
node_modules
test/temp
output
__transpiled
116 changes: 116 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
env:
node: true
es6: true
jest/globals: true

plugins:
- sonarjs
- jest
- react

extends:
- eslint:recommended
- plugin:jest/recommended
- plugin:react/recommended
- plugin:sonarjs/recommended
- plugin:security/recommended

parserOptions:
ecmaVersion: 2018
sourceType: module
ecmaFeatures:
jsx: true
settings:
react:
version: detect

rules:
# Ignore Rules
strict: 0
no-underscore-dangle: 0
no-mixed-requires: 0
no-process-exit: 0
no-warning-comments: 0
curly: 0
no-multi-spaces: 0
no-alert: 0
consistent-return: 0
consistent-this: [0, self]
func-style: 0
max-nested-callbacks: 0
camelcase: 0

# Warnings
no-debugger: 1
no-empty: 1
no-invalid-regexp: 1
no-unused-expressions: 1
no-native-reassign: 1
no-fallthrough: 1
sonarjs/cognitive-complexity: 1

# Errors
eqeqeq: 2
no-undef: 2
no-dupe-keys: 2
no-empty-character-class: 2
no-self-compare: 2
valid-typeof: 2
no-unused-vars: [2, { "args": "none" }]
handle-callback-err: 2
no-shadow-restricted-names: 2
no-new-require: 2
no-mixed-spaces-and-tabs: 2
block-scoped-var: 2
no-else-return: 2
no-throw-literal: 2
no-void: 2
radix: 2
wrap-iife: [2, outside]
no-shadow: 0
no-use-before-define: [2, nofunc]
no-path-concat: 2
valid-jsdoc: [0, {requireReturn: false, requireParamDescription: false, requireReturnDescription: false}]

# stylistic errors
no-spaced-func: 2
semi-spacing: 2
quotes: [2, 'single']
key-spacing: [2, { beforeColon: false, afterColon: true }]
indent: [2, 2]
no-lonely-if: 2
no-floating-decimal: 2
brace-style: [2, 1tbs, { allowSingleLine: true }]
comma-style: [2, last]
no-multiple-empty-lines: [2, {max: 1}]
no-nested-ternary: 2
operator-assignment: [2, always]
padded-blocks: [2, never]
quote-props: [2, as-needed]
keyword-spacing: [2, {'before': true, 'after': true, 'overrides': {}}]
space-before-blocks: [2, always]
array-bracket-spacing: [2, never]
computed-property-spacing: [2, never]
space-in-parens: [2, never]
space-unary-ops: [2, {words: true, nonwords: false}]
wrap-regex: 2
linebreak-style: [2, unix]
semi: [2, always]
arrow-spacing: [2, {before: true, after: true}]
no-class-assign: 2
no-const-assign: 2
no-dupe-class-members: 2
no-this-before-super: 2
no-var: 2
object-shorthand: [2, always]
prefer-arrow-callback: 2
prefer-const: 2
prefer-spread: 2
prefer-template: 2

# React
react/jsx-uses-react: off
react/react-in-jsx-scope: off
react/display-name: off
react/prop-types: off
react/jsx-key: off
32 changes: 0 additions & 32 deletions .github/workflows/bump.yml

This file was deleted.

2 changes: 1 addition & 1 deletion .github/workflows/issues-prs-notifications.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,4 @@ jobs:
SLACK_WEBHOOK: ${{secrets.SLACK_GITHUB_NEWISSUEPR}}
SLACK_TITLE: 💬 New Discussion 💬
SLACK_MESSAGE: ${{steps.discussionmarkdown.outputs.text}}
MSG_MINIMAL: true
MSG_MINIMAL: true
2 changes: 1 addition & 1 deletion .github/workflows/welcome-first-time-contrib.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,4 @@
# pr-message: |
# Welcome to AsyncAPI. Thanks a lot for creating your first pull request. Please check out our [contributors guide](https://github.com/asyncapi/.github/blob/master/CONTRIBUTING.md) and the instructions about a [basic recommended setup](https://github.com/asyncapi/.github/blob/master/git-workflow.md) useful for opening a pull request.

# Keep in mind there are also other channels you can use to interact with AsyncAPI community. For more details check out [this issue](https://github.com/asyncapi/asyncapi/issues/115).
# Keep in mind there are also other channels you can use to interact with AsyncAPI community. For more details check out [this issue](https://github.com/asyncapi/asyncapi/issues/115).
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,6 @@ node_modules/*

# Generated AsyncAPI output
test/output/*
output/*
.DS_Store
__transpiled
8 changes: 8 additions & 0 deletions CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# This file provides an overview of code owners in this repository.

# Each line is a file pattern followed by one or more owners.
# The last matching pattern has the most precedence.
# For more details, read the following article on GitHub: https://help.github.com/articles/about-codeowners/.

# The default owners are automatically added as reviewers when you open a pull request unless different owners are specified in the file.
* @anandsunderraman @smoya @github-actions[bot]
107 changes: 107 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
- [Overview](#overview)
- [Technical requirements](#technical-requirements)
- [Supported protocols](#supported-protocols)
- [How to use the template](#how-to-use-the-template)
* [CLI](#cli)
- [Template configuration](#template-configuration)


## Overview

This template generates a Go module that uses [watermill](https://github.com/ThreeDotsLabs/watermill) as the messaging middleware

## Technical requirements

- 1.1.0 =< [Generator](https://github.com/asyncapi/generator/) < 2.0.0,
- Generator specific [requirements](https://github.com/asyncapi/generator/#requirements)

## Supported protocols

Currently this template supports AMQP subscribers

## How to use the template

This template must be used with the AsyncAPI Generator. You can find all available options [here](https://github.com/asyncapi/generator/).

### CLI

This template has been tested to generate an AMQP subscriber for [this asyncapi.yaml file](./test/asyncapi.yaml)

#### Run the following command to generate a Go module

```bash
npm install -g @asyncapi/generator
# clone this repository and navigate to this repository
ag test/asyncapi.yaml @asyncapi/go-watermill-template -o /path/to/generated-code -p moduleName=your-go-module-name
```

Following are the options that can be passed to the generator

1. moduleName: name of the go module to be generated

#### How to use the generated code

The above code currently generates a Go module that has a AMQP subscriber.

##### Pre-requisites
To run the generated code the following needs to be installed

1. go 1.16 +
2. rabbitmq-server OR docker

##### Running the code

1. Navigate to the path where the code was generated
2. Run the following commands to download the dependencies
```bash
go mod download
go mod tidy
```
3. Currently the code does not utilize the server bindings to generate the server URI. It is currently hardcoded to point to a local instance of `rabbitmq`. It is hardcoded as `"amqp://guest:guest@localhost:5672/"` at `<generated-code>/config/server.go`. Change it as per your rabbitmq instance requirements
4. Finally to execute the code run
```bash
go run main.go
```
5. Running local instance of `rabbitmq`, navigate to it using `http://localhost:15672/` with username and password `guest`/ `guest` (These are default rabbitmq credentials).
FYI one can start an instance of `rabbitmq` using `docker` as follow
```
docker run -d -p 15672:15672 -p 5672:5672 rabbitmq:3-management
```
6. Create a queue as per the AsyncAPI spec.
This can be done either of the following ways
- Using the UI: Refer to this [article](https://www.cloudamqp.com/blog/part3-rabbitmq-for-beginners_the-management-interface.html) that walks through the process of how this can be done in the UI / RabbitMQ Admin
- `cURL` request. Default rabbitmq user is `guest` and password is `guest`
```
curl --user <rabbit-user>:<rabbit-password> -X PUT \
http://localhost:15672/api/queues/%2f/<queue-name> \
-H 'cache-control: no-cache' \
-H 'content-type: application/json' \
-d '{
"auto_delete":false,
"durable":true
}'
```
7. Publish a message to the queue as per the AsyncAPI spec. This can be done either of the following ways
- Using the UI: Refer to this [article](https://www.cloudamqp.com/blog/part3-rabbitmq-for-beginners_the-management-interface.html) that walks through the process of how this can be done in the UI / RabbitMQ Admin
- `cURL` request. Default rabbitmq user is `guest` and password is `guest`
```
curl --user <rabbit-user>:<rabbit-password> -X POST \
http://localhost:15672/api/exchanges/%2f/amq.default/publish \
-H 'cache-control: no-cache' \
-H 'content-type: application/json' \
-d ' {
"properties":{},
"routing_key":"light/measured",
"payload":"{\"id\":1,\"lumens\":2,\"sentAt\":\"2021-09-21\"}",
"payload_encoding":"string"
}'
```
8. Check the output at the terminal where `go run main.go` was running and the published message should be printed

## Template configuration

You can configure this template by passing different parameters in the Generator CLI: `-p PARAM1_NAME=PARAM1_VALUE -p PARAM2_NAME=PARAM2_VALUE`

|Name|Description|Required|Example|
|---|---|---|---|
|moduleName|Name for the generated Go module|false|`my-app`|
42 changes: 42 additions & 0 deletions components/Handlers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { render } from '@asyncapi/generator-react-sdk';
import { pascalCase } from './common';

const subscriptionFunction = (channelName, operation, message) => `
// ${operation} subscription handler for ${channelName}.
func ${operation}(msg *message.Message) error {
log.Printf("received message payload: %s", string(msg.Payload))
var lm ${message}
err := json.Unmarshal(msg.Payload, &lm)
if err != nil {
log.Printf("error unmarshalling message: %s, err is: %s", msg.Payload, err)
}
return nil
}
`;

function SubscriptionHandlers({ channels }) {
return Object.entries(channels)
.map(([channelName, channel]) => {
if (channel.hasPublish()) {
const operation = pascalCase(channel.publish().id());
const message = pascalCase(channel.publish().message(0).payload().$id());
return subscriptionFunction(channelName, operation, message);
}
return '';
});
}

export function Handlers({ moduleName, channels}) {
return `
package asyncapi
import (
"encoding/json"
"log"
"github.com/ThreeDotsLabs/watermill/message"
)
${render(<SubscriptionHandlers channels={channels} />)}
`;
}
52 changes: 52 additions & 0 deletions components/Router.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { render } from '@asyncapi/generator-react-sdk';
import { pascalCase } from './common';

const addHandlerFunction = (queue, operation) => `
r.AddNoPublisherHandler(
"${operation}", // handler name, must be unique
"${queue}", // topic from which we will read events
s,
${operation},
)
`;

function AMQPRouterRules({ channels }) {
return Object.entries(channels)
.map(([channelName, channel]) => {
if (channel.hasPublish()) {
const operation = pascalCase(channel.publish().id());
const queue = channel.bindings().amqp.queue.name;
return addHandlerFunction(queue, operation);
}
return '';
});
}

export function Router({moduleName, channels, subscriberFlags}) {
let amqpRules = '';
if (subscriberFlags.hasAMQPSub) {
amqpRules = `
// ConfigureAMQPSubscriptionHandlers configures the router with the subscription handler.
func ConfigureAMQPSubscriptionHandlers(r *message.Router, s message.Subscriber) {
${render(<AMQPRouterRules channels={channels} />)}
}
`;
}

return `
package asyncapi
import (
"github.com/ThreeDotsLabs/watermill"
"github.com/ThreeDotsLabs/watermill/message"
)
// GetRouter returns a watermill router.
func GetRouter() (*message.Router, error){
logger := watermill.NewStdLogger(false, false)
return message.NewRouter(message.RouterConfig{}, logger)
}
${amqpRules}
`;
}
Loading

0 comments on commit cfdc109

Please sign in to comment.