update ignore
This commit is contained in:
@@ -0,0 +1,150 @@
|
||||
package worker
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"service/internal/auth"
|
||||
"service/pkg/logger"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// apiLoginResponse is a helper struct to unmarshal the nested API response.
|
||||
type apiLoginResponse struct {
|
||||
Data auth.LoginResponse `json:"data"`
|
||||
}
|
||||
|
||||
// login performs the initial login to get the first set of tokens.
|
||||
func (m *Manager) login(ctx context.Context) error {
|
||||
loginURL := fmt.Sprintf("%s/auth/login", strings.TrimRight(m.cfg.SatuSehat.InternalFHIRServerURL, "/"))
|
||||
|
||||
reqBody := map[string]string{
|
||||
"email": "[email protected]",
|
||||
"password": "password123",
|
||||
}
|
||||
payloadBytes, _ := json.Marshal(reqBody)
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, "POST", loginURL, bytes.NewBuffer(payloadBytes))
|
||||
if err != nil {
|
||||
return fmt.Errorf("gagal membuat login request: %w", err)
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
logger.Default().Info("[WORKER AUTH] Melakukan login untuk mendapatkan token awal...", logger.String("url", loginURL))
|
||||
|
||||
client := &http.Client{Timeout: 15 * time.Second}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return fmt.Errorf("gagal melakukan login request: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// Baca body untuk logging jika terjadi error
|
||||
bodyBytes, readErr := io.ReadAll(resp.Body)
|
||||
if readErr != nil {
|
||||
return fmt.Errorf("gagal membaca response body login: %w", readErr)
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return fmt.Errorf("login gagal dengan status: %d, response: %s", resp.StatusCode, string(bodyBytes))
|
||||
}
|
||||
|
||||
var apiResp apiLoginResponse
|
||||
if err := json.Unmarshal(bodyBytes, &apiResp); err != nil {
|
||||
return fmt.Errorf("gagal decode response login: %w, body: %s", err, string(bodyBytes))
|
||||
}
|
||||
loginResp := apiResp.Data
|
||||
|
||||
if loginResp.AccessToken == "" || loginResp.RefreshToken == "" {
|
||||
logger.Default().Error("[WORKER AUTH] Token kosong diterima dari server", logger.Any("response", loginResp))
|
||||
return fmt.Errorf("access token atau refresh token kosong diterima dari server")
|
||||
}
|
||||
|
||||
m.accessToken = loginResp.AccessToken
|
||||
m.refreshToken = loginResp.RefreshToken
|
||||
logger.Default().Info("[WORKER AUTH] Berhasil mendapatkan token awal.")
|
||||
return nil
|
||||
}
|
||||
|
||||
// refresh uses the refresh_token to get a new access_token.
|
||||
func (m *Manager) refresh(ctx context.Context) error {
|
||||
refreshURL := fmt.Sprintf("%s/auth/refresh", strings.TrimRight(m.cfg.SatuSehat.InternalFHIRServerURL, "/"))
|
||||
|
||||
if m.refreshToken == "" {
|
||||
return fmt.Errorf("tidak ada refresh token untuk digunakan, akan mencoba login ulang")
|
||||
}
|
||||
|
||||
reqBody := auth.RefreshTokenRequest{
|
||||
RefreshToken: m.refreshToken,
|
||||
Provider: "jwt",
|
||||
}
|
||||
payloadBytes, _ := json.Marshal(reqBody)
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, "POST", refreshURL, bytes.NewBuffer(payloadBytes))
|
||||
if err != nil {
|
||||
return fmt.Errorf("gagal membuat refresh request: %w", err)
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
logger.Default().Info("[WORKER AUTH] Melakukan refresh token...", logger.String("url", refreshURL))
|
||||
|
||||
client := &http.Client{Timeout: 15 * time.Second}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return fmt.Errorf("gagal melakukan refresh request: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
bodyBytes, readErr := io.ReadAll(resp.Body)
|
||||
if readErr != nil {
|
||||
return fmt.Errorf("gagal membaca response body refresh: %w", readErr)
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return fmt.Errorf("refresh token gagal dengan status: %d, response: %s", resp.StatusCode, string(bodyBytes))
|
||||
}
|
||||
|
||||
var apiResp apiLoginResponse
|
||||
if err := json.Unmarshal(bodyBytes, &apiResp); err != nil {
|
||||
return fmt.Errorf("gagal decode response refresh: %w, body: %s", err, string(bodyBytes))
|
||||
}
|
||||
refreshResp := apiResp.Data
|
||||
|
||||
if refreshResp.AccessToken == "" {
|
||||
logger.Default().Error("[WORKER AUTH] Access token kosong diterima saat refresh", logger.Any("response", refreshResp))
|
||||
return fmt.Errorf("access token kosong diterima dari server saat refresh")
|
||||
}
|
||||
|
||||
m.accessToken = refreshResp.AccessToken
|
||||
// Update refresh token if a new one is provided
|
||||
if refreshResp.RefreshToken != "" {
|
||||
m.refreshToken = refreshResp.RefreshToken
|
||||
}
|
||||
logger.Default().Info("[WORKER AUTH] Berhasil me-refresh token.")
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetAccessToken safely retrieves the current access token.
|
||||
func (m *Manager) GetAccessToken() string {
|
||||
m.tokenMutex.RLock()
|
||||
defer m.tokenMutex.RUnlock()
|
||||
return m.accessToken
|
||||
}
|
||||
|
||||
// ForceRefreshAndGetToken tries to refresh the token, falls back to login, and returns the new token.
|
||||
func (m *Manager) ForceRefreshAndGetToken(ctx context.Context) (string, error) {
|
||||
m.tokenMutex.Lock()
|
||||
defer m.tokenMutex.Unlock()
|
||||
|
||||
if err := m.refresh(ctx); err != nil {
|
||||
logger.Default().Warn("[WORKER AUTH] Refresh token gagal, mencoba login ulang...", logger.ErrorField(err))
|
||||
if loginErr := m.login(ctx); loginErr != nil {
|
||||
return "", fmt.Errorf("fallback login juga gagal: %w", loginErr)
|
||||
}
|
||||
}
|
||||
return m.accessToken, nil
|
||||
}
|
||||
Reference in New Issue
Block a user