mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-03-30 02:40:00 +08:00
# RAGFlow Go Implementation Plan 🚀 This repository tracks the progress of porting RAGFlow to Go. We'll implement core features and provide performance comparisons between Python and Go versions. ## Implementation Checklist - [x] User Management APIs - [x] Dataset Management Operations - [x] Retrieval Test - [x] Chat Management Operations - [x] Infinity Go SDK --------- Signed-off-by: Jin Hai <haijin.chn@gmail.com> Co-authored-by: Yingfeng Zhang <yingfeng.zhang@gmail.com>
295 lines
8.6 KiB
Go
295 lines
8.6 KiB
Go
//
|
|
// Copyright 2026 The InfiniFlow Authors. All Rights Reserved.
|
|
//
|
|
// 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.
|
|
//
|
|
|
|
package server
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/spf13/viper"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
// DefaultConnectTimeout default connection timeout for external services
|
|
const DefaultConnectTimeout = 5 * time.Second
|
|
|
|
// Config application configuration
|
|
type Config struct {
|
|
Server ServerConfig `mapstructure:"server"`
|
|
Database DatabaseConfig `mapstructure:"database"`
|
|
Redis RedisConfig `mapstructure:"redis"`
|
|
Log LogConfig `mapstructure:"log"`
|
|
DocEngine DocEngineConfig `mapstructure:"doc_engine"`
|
|
RegisterEnabled int `mapstructure:"register_enabled"`
|
|
OAuth map[string]OAuthConfig `mapstructure:"oauth"`
|
|
}
|
|
|
|
// OAuthConfig OAuth configuration for a channel
|
|
type OAuthConfig struct {
|
|
DisplayName string `mapstructure:"display_name"`
|
|
Icon string `mapstructure:"icon"`
|
|
}
|
|
|
|
// ServerConfig server configuration
|
|
type ServerConfig struct {
|
|
Mode string `mapstructure:"mode"` // debug, release
|
|
Port int `mapstructure:"port"`
|
|
}
|
|
|
|
// DatabaseConfig database configuration
|
|
type DatabaseConfig struct {
|
|
Driver string `mapstructure:"driver"` // mysql
|
|
Host string `mapstructure:"host"`
|
|
Port int `mapstructure:"port"`
|
|
Database string `mapstructure:"database"`
|
|
Username string `mapstructure:"username"`
|
|
Password string `mapstructure:"password"`
|
|
Charset string `mapstructure:"charset"`
|
|
}
|
|
|
|
// LogConfig logging configuration
|
|
type LogConfig struct {
|
|
Level string `mapstructure:"level"` // debug, info, warn, error
|
|
Format string `mapstructure:"format"` // json, text
|
|
}
|
|
|
|
// DocEngineConfig document engine configuration
|
|
type DocEngineConfig struct {
|
|
Type EngineType `mapstructure:"type"`
|
|
ES *ElasticsearchConfig `mapstructure:"es"`
|
|
Infinity *InfinityConfig `mapstructure:"infinity"`
|
|
}
|
|
|
|
// EngineType document engine type
|
|
type EngineType string
|
|
|
|
const (
|
|
EngineElasticsearch EngineType = "elasticsearch"
|
|
EngineInfinity EngineType = "infinity"
|
|
)
|
|
|
|
// ElasticsearchConfig Elasticsearch configuration
|
|
type ElasticsearchConfig struct {
|
|
Hosts string `mapstructure:"hosts"`
|
|
Username string `mapstructure:"username"`
|
|
Password string `mapstructure:"password"`
|
|
}
|
|
|
|
// InfinityConfig Infinity configuration
|
|
type InfinityConfig struct {
|
|
URI string `mapstructure:"uri"`
|
|
PostgresPort int `mapstructure:"postgres_port"`
|
|
DBName string `mapstructure:"db_name"`
|
|
}
|
|
|
|
// RedisConfig Redis configuration
|
|
type RedisConfig struct {
|
|
Host string `mapstructure:"host"`
|
|
Port int `mapstructure:"port"`
|
|
Password string `mapstructure:"password"`
|
|
DB int `mapstructure:"db"`
|
|
}
|
|
|
|
var (
|
|
globalConfig *Config
|
|
globalViper *viper.Viper
|
|
zapLogger *zap.Logger
|
|
)
|
|
|
|
// Init initialize configuration
|
|
func Init(configPath string) error {
|
|
v := viper.New()
|
|
|
|
// Set configuration file path
|
|
if configPath != "" {
|
|
v.SetConfigFile(configPath)
|
|
} else {
|
|
// Try to load service_conf.yaml from conf directory first
|
|
v.SetConfigName("service_conf")
|
|
v.SetConfigType("yaml")
|
|
v.AddConfigPath("./conf")
|
|
v.AddConfigPath(".")
|
|
v.AddConfigPath("./config")
|
|
v.AddConfigPath("./internal/config")
|
|
v.AddConfigPath("/etc/ragflow/")
|
|
}
|
|
|
|
// Read environment variables
|
|
v.SetEnvPrefix("RAGFLOW")
|
|
v.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
|
|
v.AutomaticEnv()
|
|
|
|
// Read configuration file
|
|
if err := v.ReadInConfig(); err != nil {
|
|
if _, ok := err.(viper.ConfigFileNotFoundError); !ok {
|
|
return fmt.Errorf("read config file error: %w", err)
|
|
}
|
|
zapLogger.Info("Config file not found, using environment variables only")
|
|
}
|
|
|
|
// Save viper instance
|
|
globalViper = v
|
|
|
|
// Unmarshal configuration to globalConfig
|
|
// Note: This will only unmarshal fields that match the Config struct
|
|
if err := v.Unmarshal(&globalConfig); err != nil {
|
|
return fmt.Errorf("unmarshal config error: %w", err)
|
|
}
|
|
|
|
// Load REGISTER_ENABLED from environment variable (default: 1)
|
|
registerEnabled := 1
|
|
if envVal := os.Getenv("REGISTER_ENABLED"); envVal != "" {
|
|
if parsed, err := strconv.Atoi(envVal); err == nil {
|
|
registerEnabled = parsed
|
|
}
|
|
}
|
|
globalConfig.RegisterEnabled = registerEnabled
|
|
|
|
// If we loaded service_conf.yaml, map mysql fields to DatabaseConfig
|
|
if globalConfig != nil && globalConfig.Database.Host == "" {
|
|
// Try to map from mysql section
|
|
if v.IsSet("mysql") {
|
|
mysqlConfig := v.Sub("mysql")
|
|
if mysqlConfig != nil {
|
|
globalConfig.Database.Driver = "mysql"
|
|
globalConfig.Database.Host = mysqlConfig.GetString("host")
|
|
globalConfig.Database.Port = mysqlConfig.GetInt("port")
|
|
globalConfig.Database.Database = mysqlConfig.GetString("name")
|
|
globalConfig.Database.Username = mysqlConfig.GetString("user")
|
|
globalConfig.Database.Password = mysqlConfig.GetString("password")
|
|
globalConfig.Database.Charset = "utf8mb4"
|
|
}
|
|
}
|
|
}
|
|
|
|
// Map ragflow section to ServerConfig
|
|
if globalConfig != nil && globalConfig.Server.Port == 0 {
|
|
// Try to map from ragflow section
|
|
if v.IsSet("ragflow") {
|
|
ragflowConfig := v.Sub("ragflow")
|
|
if ragflowConfig != nil {
|
|
globalConfig.Server.Port = ragflowConfig.GetInt("http_port") + 2 // 9382, by default
|
|
// globalConfig.Server.Port = ragflowConfig.GetInt("http_port") // Correct
|
|
// If mode is not set, default to debug
|
|
if globalConfig.Server.Mode == "" {
|
|
globalConfig.Server.Mode = "release"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Map redis section to RedisConfig
|
|
if globalConfig != nil && globalConfig.Redis.Host != "" {
|
|
if v.IsSet("redis") {
|
|
redisConfig := v.Sub("redis")
|
|
if redisConfig != nil {
|
|
hostStr := redisConfig.GetString("host")
|
|
// Handle host:port format (e.g., "localhost:6379")
|
|
if hostStr == "" {
|
|
return fmt.Errorf("Empty host of redis configuration")
|
|
}
|
|
|
|
if idx := strings.LastIndex(hostStr, ":"); idx != -1 {
|
|
globalConfig.Redis.Host = hostStr[:idx]
|
|
if portStr := hostStr[idx+1:]; portStr != "" {
|
|
if port, err := strconv.Atoi(portStr); err == nil {
|
|
globalConfig.Redis.Port = port
|
|
}
|
|
}
|
|
} else {
|
|
return fmt.Errorf("Error address format of redis: %s", hostStr)
|
|
}
|
|
|
|
globalConfig.Redis.Password = redisConfig.GetString("password")
|
|
globalConfig.Redis.DB = redisConfig.GetInt("db")
|
|
}
|
|
}
|
|
}
|
|
|
|
// Map doc_engine section to DocEngineConfig
|
|
if globalConfig != nil && globalConfig.DocEngine.Type == "" {
|
|
// Try to map from doc_engine section
|
|
if v.IsSet("doc_engine") {
|
|
docEngineConfig := v.Sub("doc_engine")
|
|
if docEngineConfig != nil {
|
|
globalConfig.DocEngine.Type = EngineType(docEngineConfig.GetString("type"))
|
|
}
|
|
}
|
|
// Also check legacy es section for backward compatibility
|
|
if v.IsSet("es") {
|
|
esConfig := v.Sub("es")
|
|
if esConfig != nil {
|
|
if globalConfig.DocEngine.Type == "" {
|
|
globalConfig.DocEngine.Type = EngineElasticsearch
|
|
}
|
|
if globalConfig.DocEngine.ES == nil {
|
|
globalConfig.DocEngine.ES = &ElasticsearchConfig{
|
|
Hosts: esConfig.GetString("hosts"),
|
|
Username: esConfig.GetString("username"),
|
|
Password: esConfig.GetString("password"),
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if v.IsSet("infinity") {
|
|
infConfig := v.Sub("infinity")
|
|
if infConfig != nil {
|
|
if globalConfig.DocEngine.Type == "" {
|
|
globalConfig.DocEngine.Type = EngineInfinity
|
|
}
|
|
if globalConfig.DocEngine.Infinity == nil {
|
|
globalConfig.DocEngine.Infinity = &InfinityConfig{
|
|
URI: infConfig.GetString("uri"),
|
|
PostgresPort: infConfig.GetInt("postgres_port"),
|
|
DBName: infConfig.GetString("db_name"),
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Get get global configuration
|
|
func GetConfig() *Config {
|
|
return globalConfig
|
|
}
|
|
|
|
// SetLogger sets the logger instance
|
|
func SetLogger(l *zap.Logger) {
|
|
zapLogger = l
|
|
}
|
|
|
|
// PrintAll prints all configuration settings
|
|
func PrintAll() {
|
|
if globalViper == nil {
|
|
zapLogger.Info("Configuration not initialized")
|
|
return
|
|
}
|
|
|
|
allSettings := globalViper.AllSettings()
|
|
zapLogger.Info("=== All Configuration Settings ===")
|
|
for key, value := range allSettings {
|
|
zapLogger.Info("config", zap.String("key", key), zap.Any("value", value))
|
|
}
|
|
zapLogger.Info("=== End Configuration ===")
|
|
}
|