diff --git a/app/importEvents.go b/app/importEvents.go deleted file mode 100644 index ede2003..0000000 --- a/app/importEvents.go +++ /dev/null @@ -1,113 +0,0 @@ -package app - -import ( - "context" - "encoding/json" - "fmt" - "io" - "log" - "net/http" - "strings" - - "grain/server/db" - relay "grain/server/types" - - "go.mongodb.org/mongo-driver/mongo" - "golang.org/x/net/websocket" -) - -func ImportEventsHandler(w http.ResponseWriter, r *http.Request) { - if r.Method != http.MethodPost { - http.Error(w, "Invalid request method", http.StatusMethodNotAllowed) - return - } - - pubkey := r.FormValue("pubkey") - relayUrls := r.FormValue("relayUrls") - urls := strings.Split(relayUrls, ",") - - for _, url := range urls { - events, err := fetchEventsFromRelay(pubkey, url) - if err != nil { - log.Printf("Error fetching events from relay %s: %v", url, err) - http.Error(w, fmt.Sprintf("Error fetching events from relay %s", url), http.StatusInternalServerError) - return - } - - err = storeEvents(events) - if err != nil { - log.Printf("Error storing events: %v", err) - http.Error(w, "Error storing events", http.StatusInternalServerError) - return - } - } - - http.Redirect(w, r, "/", http.StatusSeeOther) -} - -func fetchEventsFromRelay(pubkey, relayUrl string) ([]relay.Event, error) { - log.Printf("Connecting to relay: %s", relayUrl) - conn, err := websocket.Dial(relayUrl, "", "http://localhost/") - if err != nil { - log.Printf("Error connecting to relay %s: %v", relayUrl, err) - return nil, err - } - defer conn.Close() - log.Printf("Connected to relay: %s", relayUrl) - - reqMessage := fmt.Sprintf(`["REQ", "import-sub", {"authors": ["%s"]}]`, pubkey) - log.Printf("Sending request: %s", reqMessage) - if _, err := conn.Write([]byte(reqMessage)); err != nil { - log.Printf("Error sending request to relay %s: %v", relayUrl, err) - return nil, err - } - - var events []relay.Event - for { - var msg []byte - if err := websocket.Message.Receive(conn, &msg); err != nil { - if err == io.EOF { - break - } - log.Printf("Error receiving message from relay %s: %v", relayUrl, err) - return nil, err - } - - log.Printf("Received message: %s", string(msg)) - - var response []interface{} - if err := json.Unmarshal(msg, &response); err != nil { - log.Printf("Error unmarshaling message from relay %s: %v", relayUrl, err) - return nil, err - } - - if response[0] == "EVENT" { - eventData, err := json.Marshal(response[2]) // Change index from 1 to 2 - if err != nil { - log.Printf("Error marshaling event data from relay %s: %v", relayUrl, err) - continue - } - var event relay.Event - if err := json.Unmarshal(eventData, &event); err != nil { - log.Printf("Error unmarshaling event data from relay %s: %v", relayUrl, err) - continue - } - events = append(events, event) - } - } - - log.Printf("Fetched %d events from relay %s", len(events), relayUrl) - return events, nil -} - -func storeEvents(events []relay.Event) error { - for _, event := range events { - collection := db.GetCollection(event.Kind) - _, err := collection.InsertOne(context.TODO(), event) - if err != nil && !mongo.IsDuplicateKeyError(err) { - log.Printf("Error inserting event into MongoDB: %v", err) - return err - } - } - return nil -} \ No newline at end of file diff --git a/app/src/api/importEvents.go b/app/src/api/importEvents.go new file mode 100644 index 0000000..b2ded5c --- /dev/null +++ b/app/src/api/importEvents.go @@ -0,0 +1,162 @@ +package api + +import ( + "context" + "encoding/json" + "fmt" + "html/template" + "io" + "log" + "net/http" + "strings" + + "grain/server/db" + relay "grain/server/types" + + "go.mongodb.org/mongo-driver/mongo" + "golang.org/x/net/websocket" +) + +type ResultData struct { + Success bool + Message string + Count int +} + +func ImportEvents(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPost { + http.Error(w, "Invalid request method", http.StatusMethodNotAllowed) + return + } + + pubkey := r.FormValue("pubkey") + relayUrls := r.FormValue("relayUrls") + urls := strings.Split(relayUrls, ",") + + var totalEvents int + var errorMessage string + + for _, url := range urls { + events, err := fetchEventsFromRelay(pubkey, url) + if err != nil { + log.Printf("Error fetching events from relay %s: %v", url, err) + errorMessage = fmt.Sprintf("Error fetching events from relay %s", url) + renderResult(w, false, errorMessage, 0) + return + } + + err = storeEvents(events) + if err != nil { + log.Printf("Error storing events: %v", err) + errorMessage = "Error storing events" + renderResult(w, false, errorMessage, 0) + return + } + + totalEvents += len(events) + } + + renderResult(w, true, "Events imported successfully", totalEvents) +} + +func renderResult(w http.ResponseWriter, success bool, message string, count int) { + tmpl, err := template.New("result").Parse(` + {{ if .Success }} +

Successfully inserted {{ .Count }} events.

+ {{ else }} +

Failed to import events: {{ .Message }}

+ {{ end }} + `) + if err != nil { + http.Error(w, "Error generating result", http.StatusInternalServerError) + return + } + + data := ResultData{ + Success: success, + Message: message, + Count: count, + } + + if err := tmpl.Execute(w, data); err != nil { + http.Error(w, "Error rendering result", http.StatusInternalServerError) + } +} + +func fetchEventsFromRelay(pubkey, relayUrl string) ([]relay.Event, error) { + log.Printf("Connecting to relay: %s", relayUrl) + conn, err := websocket.Dial(relayUrl, "", "http://localhost/") + if err != nil { + log.Printf("Error connecting to relay %s: %v", relayUrl, err) + return nil, err + } + defer conn.Close() + log.Printf("Connected to relay: %s", relayUrl) + + reqMessage := fmt.Sprintf(`["REQ", "import-sub", {"authors": ["%s"]}]`, pubkey) + log.Printf("Sending request: %s", reqMessage) + if _, err := conn.Write([]byte(reqMessage)); err != nil { + log.Printf("Error sending request to relay %s: %v", relayUrl, err) + return nil, err + } + + var events []relay.Event + for { + var msg []byte + if err := websocket.Message.Receive(conn, &msg); err != nil { + if err == io.EOF { + break + } + log.Printf("Error receiving message from relay %s: %v", relayUrl, err) + return nil, err + } + + log.Printf("Received message: %s", string(msg)) + + var response []interface{} + if err := json.Unmarshal(msg, &response); err != nil { + log.Printf("Error unmarshaling message from relay %s: %v", relayUrl, err) + return nil, err + } + + if response[0] == "EOSE" { + log.Printf("Received EOSE message from relay %s, closing connection", relayUrl) + break + } + + if response[0] == "EVENT" { + eventData, err := json.Marshal(response[2]) // Change index from 1 to 2 + if err != nil { + log.Printf("Error marshaling event data from relay %s: %v", relayUrl, err) + continue + } + var event relay.Event + if err := json.Unmarshal(eventData, &event); err != nil { + log.Printf("Error unmarshaling event data from relay %s: %v", relayUrl, err) + continue + } + events = append(events, event) + } + } + + log.Printf("Fetched %d events from relay %s", len(events), relayUrl) + return events, nil +} + +func storeEvents(events []relay.Event) error { + for _, event := range events { + collection := db.GetCollection(event.Kind) + _, err := collection.InsertOne(context.TODO(), event) + if err != nil { + if mongo.IsDuplicateKeyError(err) { + log.Printf("Duplicate event ID: %s for event kind: %d", event.ID, event.Kind) + } else { + log.Printf("Error inserting event with ID: %s for event kind: %d: %v", event.ID, event.Kind, err) + return err + } + } else { + log.Printf("Successfully inserted event with ID: %s for event kind: %d", event.ID, event.Kind) + } + } + return nil +} diff --git a/app/app.go b/app/src/app.go similarity index 100% rename from app/app.go rename to app/src/app.go diff --git a/app/fetchRecentEvents.go b/app/src/fetchRecentEvents.go similarity index 100% rename from app/fetchRecentEvents.go rename to app/src/fetchRecentEvents.go diff --git a/app/src/routes/importEvents.go b/app/src/routes/importEvents.go new file mode 100644 index 0000000..3d62c1c --- /dev/null +++ b/app/src/routes/importEvents.go @@ -0,0 +1,15 @@ +package routes + +import ( + app "grain/app/src" + "net/http" +) + +func ImportEvents(w http.ResponseWriter, r *http.Request) { + data := app.PageData{ + Title: "Import Events", + } + + // Call RenderTemplate with the specific template for this route + app.RenderTemplate(w, data, "importEvents.html") +} diff --git a/app/views/importEvents.html b/app/views/importEvents.html new file mode 100644 index 0000000..92619ef --- /dev/null +++ b/app/views/importEvents.html @@ -0,0 +1,53 @@ +{{define "view"}} +
+
You are now viewing the {{.Title}}
+
+
+
+ + +
+
+ + +
+ +
+
+
+
+ +
+{{end}} diff --git a/app/views/index.html b/app/views/index.html index 75434eb..ca43f6c 100644 --- a/app/views/index.html +++ b/app/views/index.html @@ -12,38 +12,13 @@ {{end}} --> -
-
-
- - -
-
- - -
- -
-
+ Import Events + {{end}} diff --git a/app/views/templates/layout.html b/app/views/templates/layout.html index 7451513..4423bdc 100644 --- a/app/views/templates/layout.html +++ b/app/views/templates/layout.html @@ -26,6 +26,26 @@ {{.Title}} + {{template "header" .}} {{template "view" .}} {{template "footer" .}} diff --git a/main.go b/main.go index b006a75..8188f0d 100644 --- a/main.go +++ b/main.go @@ -2,7 +2,9 @@ package main import ( "fmt" - "grain/app" + app "grain/app/src" + "grain/app/src/api" + "grain/app/src/routes" "grain/config" configTypes "grain/config/types" relay "grain/server" @@ -47,7 +49,8 @@ func main() { func setupRoutes() *http.ServeMux { mux := http.NewServeMux() mux.HandleFunc("/", ListenAndServe) - mux.HandleFunc("/import-events", app.ImportEventsHandler) + mux.HandleFunc("/import-results", api.ImportEvents) + mux.HandleFunc("/import-events", routes.ImportEvents) mux.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("app/static")))) mux.HandleFunc("/favicon.ico", func(w http.ResponseWriter, r *http.Request) { http.ServeFile(w, r, "app/static/img/favicon.ico")