<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://tech.uvoo.io/index.php?action=history&amp;feed=atom&amp;title=Go_postgres_simple_memory_sync</id>
	<title>Go postgres simple memory sync - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://tech.uvoo.io/index.php?action=history&amp;feed=atom&amp;title=Go_postgres_simple_memory_sync"/>
	<link rel="alternate" type="text/html" href="https://tech.uvoo.io/index.php?title=Go_postgres_simple_memory_sync&amp;action=history"/>
	<updated>2026-04-19T17:29:35Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.35.2</generator>
	<entry>
		<id>https://tech.uvoo.io/index.php?title=Go_postgres_simple_memory_sync&amp;diff=5547&amp;oldid=prev</id>
		<title>Busk: Created page with &quot;``` package main  import (         &quot;context&quot;         &quot;database/sql&quot;         &quot;fmt&quot;         &quot;log&quot;         &quot;net/http&quot;         &quot;sync&quot;         &quot;time&quot;          _ &quot;github.com/lib/pq&quot;...&quot;</title>
		<link rel="alternate" type="text/html" href="https://tech.uvoo.io/index.php?title=Go_postgres_simple_memory_sync&amp;diff=5547&amp;oldid=prev"/>
		<updated>2025-03-29T19:24:16Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;quot;``` package main  import (         &amp;quot;context&amp;quot;         &amp;quot;database/sql&amp;quot;         &amp;quot;fmt&amp;quot;         &amp;quot;log&amp;quot;         &amp;quot;net/http&amp;quot;         &amp;quot;sync&amp;quot;         &amp;quot;time&amp;quot;          _ &amp;quot;github.com/lib/pq&amp;quot;...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;```&lt;br /&gt;
package main&lt;br /&gt;
&lt;br /&gt;
import (&lt;br /&gt;
        &amp;quot;context&amp;quot;&lt;br /&gt;
        &amp;quot;database/sql&amp;quot;&lt;br /&gt;
        &amp;quot;fmt&amp;quot;&lt;br /&gt;
        &amp;quot;log&amp;quot;&lt;br /&gt;
        &amp;quot;net/http&amp;quot;&lt;br /&gt;
        &amp;quot;sync&amp;quot;&lt;br /&gt;
        &amp;quot;time&amp;quot;&lt;br /&gt;
&lt;br /&gt;
        _ &amp;quot;github.com/lib/pq&amp;quot; // PostgreSQL driver&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
type User struct {&lt;br /&gt;
        Username string&lt;br /&gt;
        Password string&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
type UserStore struct {&lt;br /&gt;
        mu    sync.RWMutex&lt;br /&gt;
        users map[string]User&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
func NewUserStore() *UserStore {&lt;br /&gt;
        return &amp;amp;UserStore{&lt;br /&gt;
                users: make(map[string]User),&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
func (us *UserStore) Get(username string) (User, bool) {&lt;br /&gt;
        us.mu.RLock()&lt;br /&gt;
        defer us.mu.RUnlock()&lt;br /&gt;
        user, ok := us.users[username]&lt;br /&gt;
        return user, ok&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
func (us *UserStore) Set(username string, user User) {&lt;br /&gt;
        us.mu.Lock()&lt;br /&gt;
        defer us.mu.Unlock()&lt;br /&gt;
        us.users[username] = user&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
func (us *UserStore) Delete(username string) {&lt;br /&gt;
        us.mu.Lock()&lt;br /&gt;
        defer us.mu.Unlock()&lt;br /&gt;
        delete(us.users, username)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
func syncUsers(ctx context.Context, db *sql.DB, userStore *UserStore, interval time.Duration) {&lt;br /&gt;
        ticker := time.NewTicker(interval)&lt;br /&gt;
        defer ticker.Stop()&lt;br /&gt;
&lt;br /&gt;
        for {&lt;br /&gt;
                select {&lt;br /&gt;
                case &amp;lt;-ticker.C:&lt;br /&gt;
                        if err := loadUsers(db, userStore); err != nil {&lt;br /&gt;
                                log.Printf(&amp;quot;Error loading users: %v&amp;quot;, err)&lt;br /&gt;
                        }&lt;br /&gt;
                case &amp;lt;-ctx.Done():&lt;br /&gt;
                        log.Println(&amp;quot;User sync stopped&amp;quot;)&lt;br /&gt;
                        return&lt;br /&gt;
                }&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
func loadUsers(db *sql.DB, userStore *UserStore) error {&lt;br /&gt;
        rows, err := db.Query(&amp;quot;SELECT username, password FROM users&amp;quot;)&lt;br /&gt;
        if err != nil {&lt;br /&gt;
                return fmt.Errorf(&amp;quot;query failed: %w&amp;quot;, err)&lt;br /&gt;
        }&lt;br /&gt;
        defer rows.Close()&lt;br /&gt;
&lt;br /&gt;
        newUsers := make(map[string]User)&lt;br /&gt;
&lt;br /&gt;
        for rows.Next() {&lt;br /&gt;
                var user User&lt;br /&gt;
                if err := rows.Scan(&amp;amp;user.Username, &amp;amp;user.Password); err != nil {&lt;br /&gt;
                        return fmt.Errorf(&amp;quot;scan failed: %w&amp;quot;, err)&lt;br /&gt;
                }&lt;br /&gt;
                newUsers[user.Username] = user&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if err := rows.Err(); err != nil {&lt;br /&gt;
                return fmt.Errorf(&amp;quot;rows iteration failed: %w&amp;quot;, err)&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        userStore.mu.Lock()&lt;br /&gt;
        userStore.users = newUsers&lt;br /&gt;
        userStore.mu.Unlock()&lt;br /&gt;
&lt;br /&gt;
        log.Println(&amp;quot;Users synchronized&amp;quot;)&lt;br /&gt;
        return nil&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
func basicAuth(userStore *UserStore, handler http.HandlerFunc) http.HandlerFunc {&lt;br /&gt;
        return func(w http.ResponseWriter, r *http.Request) {&lt;br /&gt;
                username, password, ok := r.BasicAuth()&lt;br /&gt;
                if !ok {&lt;br /&gt;
                        w.Header().Set(&amp;quot;WWW-Authenticate&amp;quot;, `Basic realm=&amp;quot;Restricted&amp;quot;`)&lt;br /&gt;
                        http.Error(w, &amp;quot;Unauthorized&amp;quot;, http.StatusUnauthorized)&lt;br /&gt;
                        return&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                user, ok := userStore.Get(username)&lt;br /&gt;
                if !ok || user.Password != password {&lt;br /&gt;
                        w.Header().Set(&amp;quot;WWW-Authenticate&amp;quot;, `Basic realm=&amp;quot;Restricted&amp;quot;`)&lt;br /&gt;
                        http.Error(w, &amp;quot;Unauthorized&amp;quot;, http.StatusUnauthorized)&lt;br /&gt;
                        return&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                handler(w, r)&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
func main() {&lt;br /&gt;
        connStr := &amp;quot;postgres://user:password@host/dbname?sslmode=disable&amp;quot; // Replace with your connection string&lt;br /&gt;
        db, err := sql.Open(&amp;quot;postgres&amp;quot;, connStr)&lt;br /&gt;
        if err != nil {&lt;br /&gt;
                log.Fatalf(&amp;quot;Error opening database: %v&amp;quot;, err)&lt;br /&gt;
        }&lt;br /&gt;
        defer db.Close()&lt;br /&gt;
&lt;br /&gt;
        if err := db.Ping(); err != nil {&lt;br /&gt;
                log.Fatalf(&amp;quot;Error pinging database: %v&amp;quot;, err)&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        userStore := NewUserStore()&lt;br /&gt;
        ctx, cancel := context.WithCancel(context.Background())&lt;br /&gt;
        defer cancel()&lt;br /&gt;
&lt;br /&gt;
        go syncUsers(ctx, db, userStore, 5*time.Second) // Sync every 5 seconds&lt;br /&gt;
&lt;br /&gt;
        http.HandleFunc(&amp;quot;/&amp;quot;, basicAuth(userStore, func(w http.ResponseWriter, r *http.Request) {&lt;br /&gt;
                fmt.Fprint(w, &amp;quot;Authenticated!\n&amp;quot;)&lt;br /&gt;
        }))&lt;br /&gt;
&lt;br /&gt;
        log.Println(&amp;quot;Server listening on :8080&amp;quot;)&lt;br /&gt;
        if err := http.ListenAndServe(&amp;quot;:8080&amp;quot;, nil); err != nil {&lt;br /&gt;
                log.Fatalf(&amp;quot;Error starting server: %v&amp;quot;, err)&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
```&lt;/div&gt;</summary>
		<author><name>Busk</name></author>
	</entry>
</feed>