# Allow local `replace` directives. Default is false.
# Allow local `replace` directives. Default is false.
replace-local:true
replace-local:true
@ -363,6 +384,7 @@ linters-settings:
retract-allow-no-explanation:false
retract-allow-no-explanation:false
# Forbid the use of the `exclude` directives. Default is false.
# Forbid the use of the `exclude` directives. Default is false.
exclude-forbidden:false
exclude-forbidden:false
gomodguard:
gomodguard:
allowed:
allowed:
modules:
modules:
@ -426,9 +448,6 @@ linters-settings:
checks:["all"]
checks:["all"]
govet:
govet:
# report about shadowed variables
check-shadowing:false
# settings per analyzer
# settings per analyzer
settings:
settings:
printf:# analyzer name, run `go tool vet help` to see all analyzers
printf:# analyzer name, run `go tool vet help` to see all analyzers
@ -445,15 +464,25 @@ linters-settings:
disable:
disable:
- shadow
- shadow
disable-all:false
disable-all:false
# depguard:
# list-type: blacklist
# include-go-root: false
# packages:
# - github.com/Sirupsen/logrus
# packages-with-error-message:
# # specify an error message to output when a blacklisted package is used
# - github.com/Sirupsen/logrus: "logging is allowed only by logutils.Log"
depguard:
rules:
prevent_unmaintained_packages:
list-mode:lax# allow unless explicitely denied
files:
- $all
- "!$test"
allow:
- $gostd
deny:
- pkg:io/ioutil
desc:"replaced by io and os packages since Go 1.16: https://tip.golang.org/doc/go1.16#ioutil"
- pkg:github.com/OpenIMSDK
desc:"The OpenIM organization has been replaced with lowercase, please do not use uppercase organization name, you will use openimsdk"
- pkg:log
desc:"We have a wrapped log package at openim, we recommend you to use our wrapped log package, https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/logging.md"
- pkg:errors
desc:"We have a wrapped errors package at openim, we recommend you to use our wrapped errors package, https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md"
importas:
importas:
# if set to `true`, force to use alias.
# if set to `true`, force to use alias.
@ -463,6 +492,8 @@ linters-settings:
# using `servingv1` alias for `knative.dev/serving/pkg/apis/serving/v1` package
# using `servingv1` alias for `knative.dev/serving/pkg/apis/serving/v1` package
- pkg:knative.dev/serving/pkg/apis/serving/v1
- pkg:knative.dev/serving/pkg/apis/serving/v1
alias:servingv1
alias:servingv1
- pkg:gopkg.in/yaml.v2
alias:yaml
# using `autoscalingv1alpha1` alias for `knative.dev/serving/pkg/apis/autoscaling/v1alpha1` package
# using `autoscalingv1alpha1` alias for `knative.dev/serving/pkg/apis/autoscaling/v1alpha1` package
Configuration files can be automatically generated using the `make init` command or the `./scripts/init-config.sh` script. These scripts conveniently extract templates from the `templates` directory and generate or update actual configuration files in the root directory.
### 3.1. <aname='HowtoUseinit-config.shScript'></a>How to Use `init-config.sh` Script
```bash
$ ./scripts/init-config.sh --help
Usage: init-config.sh [options]
Options:
-h, --help Show this help message
--force Overwrite existing files without prompt
--skip Skip generation if file exists
--examples Generate example files
--clean-config Clean all configuration files
--clean-examples Clean all example files
```
### 3.2. <aname='ExamplesofOperations'></a>Examples of Operations
- Generate all template configuration files:
```bash
$ ./scripts/init-config.sh --examples
```
- Force overwrite existing configuration files:
```bash
$ ./scripts/init-config.sh --force
```
### 3.3. <aname='PointstoNote'></a>Points to Note
- **Template files should not be directly modified**: Files in the `template` directory are templates included in source code management. Direct modification may lead to version conflicts or management issues.
- **Operations for Windows Users**: Windows users can use the `cp` command to copy files from the `template` directory to the `config/` directory and then modify the configuration items as needed.
Welcome to our project's `examples` directory! This directory contains a range of example files, showcasing various configurations and settings of our software. These examples are intended to provide you with templates that can serve as a starting point for your own configurations.
### 4.1. <aname='Overview'></a>Overview
In this directory, you'll find examples suitable for a variety of use cases. Each file is a template with default values and configurations, demonstrating best practices and typical scenarios. Whether you're just getting started or looking to implement complex settings, these examples should help you get on the right track.
### 4.2. <aname='Structure'></a>Structure
Here's a quick overview of the contents in this directory:
- `env-example.yaml`: Demonstrates how to set up environmental variables.
- `openim-example.yaml`: Example configuration file for the OpenIM application.
- `prometheus-example.yml`: Example configuration for monitoring with Prometheus.
- `alertmanager-example.yml`: Template for setting up Alertmanager configuration.
### 4.3. <aname='HowtoUseTheseExamples'></a>How to Use These Examples
To use these examples, simply copy the relevant files to your working directory and rename them as needed (for example, removing the `-example` suffix). Then, modify the files according to your needs.
### 4.4. <aname='TipsforUsingExampleFiles:'></a>Tips for Using Example Files:
1. **Read Comments**: Each file contains comments explaining the various sections and settings. Make sure to read these comments for a better understanding of how to customize the file.
2. **Check Required Changes**: Some examples might require mandatory changes before they can be used effectively (such as setting specific environmental variables).
3. **Version Compatibility**: Ensure that the example files are compatible with the version of the software you are using.
## 6. <aname='VersionManagementandUpgrading'></a>Version Management and Upgrading
When managing and upgrading the `config` directory's versions, it is crucial to ensure that the configuration files in both the local `config/` and `config/templates/` directories are kept in sync. This process can ensure that your configuration files are consistent with the latest standard templates, while also maintaining custom settings.
### 6.1. <aname='PullingtheLatestCode'></a>Pulling the Latest Code
First, ensure that your local repository is in sync with the remote repository. This can be achieved by pulling the latest code:
```bash
$ git pull
```
### 6.2. <aname='GeneratingtheLatestExampleConfigurationFiles'></a>Generating the Latest Example Configuration Files
Next, generate the latest example configuration files. This can be done by running the `init-config.sh` script, using the `--examples` option to generate example files, and the `--skip` option to avoid overwriting existing configuration files:
Once the latest example configuration files are generated, you need to compare the configuration files in the `config/` and `config/templates/` directories to find any potential differences. This step ensures that you can identify and integrate any important updates or changes. Tools like `diff` can be helpful in completing this step:
Based on the comparison results, manually update the configuration files in the `config/` directory to reflect the latest configurations in `config/templates/`. During this process, ensure to retain any custom configuration settings.
### 6.5. <aname='UpdatingBinaryFilesandRestartingServices'></a>Updating Binary Files and Restarting Services
After updating the configuration files, the next step is to update any related binary files. This typically involves downloading and installing the latest version of the application or service. Depending on the specific application or service, this might involve running specific update scripts or directly downloading the latest version from official sources.
Once the binary files are updated, the services need to be restarted to apply the new configurations. Make sure to conduct necessary checks before restarting to ensure the correctness of the configurations.
### 6.6. <aname='BestPracticesforVersionManagement'></a>Best Practices for Version Management
- **Record Changes**: When committing changes to a version control system, ensure to log detailed change logs.
- **Stay Synced**: Regularly sync with the remote repository to ensure that your local configurations are in line with the latest developments.
- **Backup**: Backup your current configurations before making any significant changes, so that you can revert to a previous state if necessary.
By following these steps and best practices, you can ensure effective management and smooth upgrading of your `config` directory.
## 7. <aname='HowtoContribute'></a>How to Contribute
If you have an understanding of the logic behind OpenIM's configuration generation, then you will clearly know where to make modifications to contribute code.
First, it is recommended to read the [OpenIM Configuration Items Document](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/environment.md). This will help you understand the roles of various configuration items and how they affect the operation of OpenIM.
To contribute to OpenIM, focus on the `./deployments/templates` directory. This contains various configuration template files, which are the basis for generating the final configuration files.
When making modifications, ensure that your changes align with OpenIM's configuration requirements and logic. This may involve adding new template files or modifying existing files to reflect new configuration options or structural changes.
### 7.3. <aname='UpdatingConfigurationCenterScripts'></a>Updating Configuration Center Scripts
In addition to modifying template files, pay attention to the `./scripts/install/environment.sh` script. In this script, you may need to add or modify environment variables.
This script is responsible for defining environment variables that influence configuration generation. Therefore, any new configuration items or modifications to existing items need to be reflected here.
### 7.4. <aname='ConfigurationFileGenerationProcess'></a>Configuration File Generation Process
The essence of the `make init` command is to use the environment variables defined in `/scripts/install/environment.sh` to render the template files in the `./deployments/templates` directory, thereby generating the final configuration files.
When contributing code, ensure that your changes work smoothly in this process and do not cause errors during configuration file generation.
- **Code Review**: Ensure your changes have passed code review. This typically means that the code should be clear, easy to understand, and adhere to the project's coding style and best practices.
- **Testing**: Before submitting changes, conduct thorough tests to ensure new or modified configurations work as expected and do not negatively impact existing functionalities.
- **Documentation**: If you have added a new configuration option or made significant changes to an existing one, update the relevant documentation to assist other users and developers in understanding and utilizing these changes.
### 7.6. <aname='SubmissionandReview'></a>Submission and Review
After completing your changes, submit your code to the OpenIM repository in the form of a Pull Request (PR). The PR will be reviewed by the project maintainers and you may be asked to make further modifications or provide additional information.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Determines if a message should be sent. If set to false, it triggers a silent sync without a message. If true, it requires triggering a conversation.
# For rpc notification, send twice: once as a message and once as a notification.
# The options field 'isNotification' indicates if it's a notification.
groupCreated:
isSendMsg:true
# Reliability level of the message sending.
# Set to 1 to send only when online, 2 for guaranteed delivery.
reliabilityLevel:1
# This setting is effective only when 'isSendMsg' is true.
# It controls whether to count unread messages.
unreadCount:false
# Configuration for offline push notifications.
offlinePush:
# Enables or disables offline push notifications.
enable:false
# Title for the notification when a group is created.
title:"create group title"
# Description for the notification.
desc:"create group desc"
# Additional information for the notification.
ext:"create group ext"
# Content type is not added here.
# Content should use a JSON structure conforming to the protobuf format.
- Use `_` as a prefix for unexported top-level constants and variables.
- This example emphasizes using PascalCase for exported constants and camelCase for unexported ones, avoiding all caps and underscores.
```go
```go
// bad
// bad
const (
const (
defaultHost = "127.0.0.1"
MAX_COUNT = 100
defaultPort = 8080
timeout = 30
)
)
// good
// good
const (
const (
_defaultHost = "127.0.0.1"
MaxCount = 100 // Exported constants should use PascalCase.
_defaultPort = 8080
defaultTimeout = 30 // Unexported constants should use camelCase.
)
)
```
```
- Grouping related constants enhances organization and readability, especially when there are multiple constants related to a particular feature or configuration.
```go
// bad
const apiVersion = "v1"
const retryInterval = 5
// good
const (
ApiVersion = "v1" // Group related constants together for better organization.
RetryInterval = 5
)
```
- The "good" practice utilizes iota for a clear, concise, and auto-incrementing way to define enumerations, reducing the potential for errors and improving maintainability.
```go
// bad
const (
StatusActive = 0
StatusInactive = 1
StatusUnknown = 2
)
// good
const (
StatusActive = iota // Use iota for simple and efficient constant enumerations.
StatusInactive
StatusUnknown
)
```
- Specifying types explicitly improves clarity, especially when the purpose or type of a constant might not be immediately obvious. Additionally, adding comments to exported constants or those whose purpose isn't clear from the name alone can greatly aid in understanding the code.
```go
// bad
const serverAddress = "localhost:8080"
const debugMode = 1 // Is this supposed to be a boolean or an int?
// good
const ServerAddress string = "localhost:8080" // Specify type for clarity.
// DebugMode indicates if the application should run in debug mode (true for debug mode).
const DebugMode bool = true
```
- By defining a contextKey type and making userIDKey of this type, you avoid potential collisions with other context keys. This approach leverages Go's type system to provide compile-time checks against misuse.
```go
// bad
const userIDKey = "userID"
// In this example, userIDKey is a string type, which can lead to conflicts or accidental misuse because string keys are prone to typos and collisions in a global namespace.
// good
type contextKey string
const userIDKey contextKey = "userID"
```
- Embedded types (such as mutexes) should be at the top of the field list within the struct, and there must be a blank line separating embedded fields from regular fields.
- Embedded types (such as mutexes) should be at the top of the field list within the struct, and there must be a blank line separating embedded fields from regular fields.
```go
```go
@ -274,8 +335,6 @@ The use of `panic` should be carefully controlled in Go applications to ensure p
- **Restricted Use in Main Package:** In the main package, the use of `panic` should be reserved for situations where the program is entirely inoperable, such as failure to open essential files, inability to connect to the database, or other critical startup issues. Even in these scenarios, prefer using structured error handling to terminate the program.
- **Restricted Use in Main Package:** In the main package, the use of `panic` should be reserved for situations where the program is entirely inoperable, such as failure to open essential files, inability to connect to the database, or other critical startup issues. Even in these scenarios, prefer using structured error handling to terminate the program.
- **Use `log.Fatal` for Critical Errors:** Instead of panicking, use `log.Fatal` to log critical errors that prevent the program from operating normally. This approach allows the program to terminate while ensuring the error is properly logged for troubleshooting.
- **Prohibition on Exportable Interfaces:** Exportable interfaces must not invoke `panic`. They should handle errors gracefully and return errors as part of their contract.
- **Prohibition on Exportable Interfaces:** Exportable interfaces must not invoke `panic`. They should handle errors gracefully and return errors as part of their contract.
- **Prefer Errors Over Panic:** It is recommended to use error returns instead of panic to convey errors within a package. This approach promotes error handling that integrates smoothly with Go's error handling idioms.
- **Prefer Errors Over Panic:** It is recommended to use error returns instead of panic to convey errors within a package. This approach promotes error handling that integrates smoothly with Go's error handling idioms.
@ -357,27 +416,31 @@ The naming convention is a very important part of the code specification. A unif
- Don't use broad, meaningless package names like common, util, shared or lib.
- Don't use broad, meaningless package names like common, util, shared or lib.
- The package name should be simple and clear, such as net, time, log.
- The package name should be simple and clear, such as net, time, log.
### 2.2 Function Naming
- The function name is in camel case, and the first letter is uppercase or lowercase according to the access control decision,For example: `MixedCaps` or `mixedCaps`.
### 2.2 Function Naming Conventions
- Code automatically generated by code generation tools (such as `xxxx.pb.go`) and underscores used to group related test cases (such as `TestMyFunction_WhatIsBeingTested`) exclude this rule.
Function names should adhere to the following guidelines, inspired by OpenIM’s standards and Google’s Go Style Guide:
- Use camel case for function names. Start with an uppercase letter for public functions (`MixedCaps`) and a lowercase letter for private functions (`mixedCaps`).
- Exceptions to this rule include code automatically generated by tools (e.g., `xxxx.pb.go`) and test functions that use underscores for clarity (e.g., `TestMyFunction_WhatIsBeingTested`).
### 2.3 File and Directory Naming Practices
To maintain consistency and readability across the OpenIM project, observe the following naming practices:
**File Names:**
- Use underscores (`_`) as the default separator in filenames, keeping them short and descriptive.
- Both hyphens (`-`) and underscores (`_`) are allowed, but underscores are preferred for general use.
In accordance with the naming conventions adopted by OpenIM and drawing reference from the Google Naming Conventions as per the guidelines available at https://google.github.io/styleguide/go/, the following expectations for naming practices within the project are set forth:
**Script and Markdown Files:**
- Prefer hyphens (`-`) for shell scripts and Markdown (`.md`) files to enhance searchability and web compatibility.
1. **File Names:**
**Directories:**
+ Both hyphens (`-`) and underscores (`_`) are permitted when naming files.
- Name directories with hyphens (`-`) exclusively to separate words, ensuring consistency and readability.
+ A preference is established for the use of underscores (`_`), suggesting it as the best practice in general scenarios.
2. **Script and Markdown Files:**
+ For shell scripts (bash files) and Markdown (`.md`) documents, the use of hyphens (`-`) is recommended.
+ This recommendation is based on the improved searchability and compatibility in web browsers when hyphens are used in names.
3. **Directories:**
+ A consistent approach is mandated for naming directories, exclusively using hyphens (`-`) to separate words within directory names.
Remember to keep filenames lowercase and use meaningful, concise identifiers to facilitate better organization and navigation within the project.
### 2.3 File Naming
- Keep the filename short and meaningful.
- Filenames should be lowercase and use underscores to separate words.
### 2.4 Structure Naming
### 2.4 Structure Naming
@ -478,9 +541,9 @@ var LintGonicMapper = GonicMapper{
- If the variable type is bool, the name should start with Has, Is, Can or Allow, for example:
- If the variable type is bool, the name should start with Has, Is, Can or Allow, for example:
In the realm of software development, especially within Go language projects, documentation plays a crucial role in ensuring code maintainability and ease of use. Properly written and accurate documentation is not only essential for understanding and utilizing software effectively but also needs to be easy to write and maintain. This principle is at the heart of OpenIM's approach to supporting commands and generating documentation.
## Supported Commands in OpenIM
OpenIM leverages Go language's documentation standards to facilitate clear and maintainable code documentation. Below are some of the key commands used in OpenIM for documentation purposes:
### `go doc` Command
The `go doc` command is used to print documentation for Go language entities such as variables, constants, functions, structures, and interfaces. This command allows specifying the identifier of the program entity to tailor the output. Examples of `go doc` command usage include:
- `go doc sync.WaitGroup.Add` prints the documentation for a specific method of a type in a package.
- `go doc -u -all sync.WaitGroup` displays all program entities, including unexported ones, for a specified type.
- `go doc -u sync` outputs all program entities for a specified package, focusing on exported ones without detailed comments.
### `godoc` Command
For environments lacking internet access, the `godoc` command serves to view the Go language standard library and project dependency library documentation in a web format. Notably, post-Go 1.12 versions, `godoc` is not part of the Go compiler suite. It can be installed using:
```shell
go get -u -v golang.org/x/tools/cmd/godoc
```
The `godoc` command, once running, hosts a local web server (by default on port 6060) to facilitate documentation browsing at http://127.0.0.1:6060. It generates documentation based on the GOROOT and GOPATH directories, showcasing both the project's own documentation and that of third-party packages installed via `go get`.
### Custom Documentation Generation Commands in OpenIM
OpenIM includes a suite of commands aimed at initializing, generating, and maintaining project documentation and associated files. Some notable commands are:
- `gen.init`: Initializes the OpenIM server project.
- `gen.docgo`: Generates missing `doc.go` files for Go packages, crucial for package-level documentation.
- `gen.errcode.doc`: Generates markdown documentation for OpenIM error codes.
- `gen.ca`: Generates CA files for all certificates, enhancing security documentation.
These commands underscore the project's commitment to thorough and accessible documentation, supporting both developers and users alike.
## Writing Your Own Documentation
When creating documentation for Go projects, including OpenIM, it's important to follow certain practices:
1. **Commenting**: Use single-line (`//`) and block (`/* */`) comments to provide detailed documentation within the code. Block comments are especially useful for package documentation, which should immediately precede the package statement without any intervening blank lines.
2. **Overview Section**: To create an overview section in the documentation, place a block comment directly before the package statement. This section should succinctly describe the package's purpose and functionality.
3. **Detailed Descriptions**: Comments placed before functions, structures, or variables will be used to generate detailed descriptions in the documentation. Follow the same commenting rules as for the overview section.
4. **Examples**: Include example functions prefixed with `Example` to demonstrate usage. Output from these examples can be documented at the end of the function, starting with `// Output:` followed by the expected result.
Through adherence to these documentation practices, OpenIM ensures that its codebase remains accessible, maintainable, and easy to use for developers and users alike.
@ -66,7 +66,7 @@ The `CodeError` interface is designed to provide a unified mechanism for error h
## Logging Standards and Code Examples
## Logging Standards and Code Examples
In the OpenIM project, we use the unified logging package `github.com/OpenIMSDK/tools/log` for logging to achieve efficient log management and analysis. This logging package supports structured logging formats, making it easier for developers to handle log information.
In the OpenIM project, we use the unified logging package `github.com/openimsdk/tools/log` for logging to achieve efficient log management and analysis. This logging package supports structured logging formats, making it easier for developers to handle log information.
### Logger Interface and Implementation
### Logger Interface and Implementation
@ -96,7 +96,7 @@ func main() {
## Error Handling and Code Examples
## Error Handling and Code Examples
We use the `github.com/OpenIMSDK/tools/errs` package for unified error handling and wrapping.
We use the `github.com/openimsdk/tools/errs` package for unified error handling and wrapping.
- `msg string`: The message text to append to the error.
- `kv ...any`: A variable number of parameters used to pass key-value pairs. `any` was introduced in Go 1.18 and is equivalent to `interface{}`, meaning any type.
2. **Logic**:
- If there are no key-value pairs (`kv` is empty):
- If `msg` is also empty, use `errors.WithStack(err)` to return the original error with the call stack appended.
- If `msg` is not empty, use `errors.WithMessage(err, msg)` to append the message text to the original error.
- If there are key-value pairs, the function constructs a string containing the message text and all key-value pairs. The key-value pairs are added in the format `"key=value"`, separated by commas. If a message text is provided, it is added first, followed by a space.
3. **Key-Value Pair Formatting**:
- A loop iterates over all the key-value pairs, processing one pair at a time.
- The `toString` function (although not provided in the code, we can assume it converts any type to a string) is used to convert both keys and values to strings, and they are added to a `bytes.Buffer` in the format `"key=value"`.
4. **Result**:
- Use `errors.WithMessage(err, buf.String())` to append the constructed message text to the original error, and return this new error object.
Next, let's demonstrate several ways to use the `WrapMsg` function:
**Example 1: No Additional Information**
```go
// "github.com/openimsdk/tools/errs"
err := errors.New("original error")
wrappedErr := errs.WrapMsg(err, "")
// wrappedErr will contain the original error and its call stack
// wrappedErr will contain the original error, call stack, and "user=john_doe, action=login"
```
> [!TIP] WThese examples demonstrate how the `errs.WrapMsg` function can flexibly handle error messages and context data, helping developers to more effectively track and debug their programs.
### Example 5: Dynamic Key-Value Pairs from Context
Suppose we have some runtime context variables, such as a user ID and the type of operation being performed, and we want to include these variables in the error message. This can help with later debugging and identifying the specific environment of the issue.
// wrappedErr will contain the original error, call stack, and "operation failed user=user123, action=update profile, code=500, url=http://example.com/updateProfile"
```
> [!TIP]In this example, the `WrapMsg` function accepts not just a static error message and additional information, but also dynamic key-value pairs generated from the code's execution context, such as the user ID, operation type, error code, and the URL of the request. Including this contextual information in the error message makes it easier for developers to understand and resolve the issue.