func main() { log.Printf("Server pid=%d started with processes: %d", os.Getpid(), runtime.GOMAXPROCS(runtime.NumCPU())) var configfile = flag.String("config", "./tinode.conf", "Path to config file.") // Path to static content. var staticPath = flag.String("static_data", "", "Path to /static data for the server.") var listenOn = flag.String("listen", "", "Override tinode.conf address and port to listen on.") flag.Parse() log.Printf("Using config from: '%s'", *configfile) var config configType if raw, err := ioutil.ReadFile(*configfile); err != nil { log.Fatal(err) } else if err = json.Unmarshal(raw, &config); err != nil { log.Fatal(err) } if *listenOn != "" { config.Listen = *listenOn } var err = store.Open(config.Adapter, string(config.AdapterConfig)) if err != nil { log.Fatal("Failed to connect to DB: ", err) } defer func() { store.Close() log.Println("Closed database connection(s)") }() // Keep inactive LP sessions for 70 seconds globals.sessionStore = NewSessionStore(IDLETIMEOUT + 15*time.Second) globals.hub = newHub() // Serve static content from the directory in -static_data flag if that's // available, if not assume current dir. if *staticPath != "" { http.Handle("/x/", http.StripPrefix("/x/", http.FileServer(http.Dir(*staticPath)))) } else { path, err := os.Getwd() if err != nil { log.Fatal(err) } http.Handle("/x/", http.StripPrefix("/x/", http.FileServer(http.Dir(path+"/static")))) } // Streaming channels // Handle websocket clients. WS must come up first, so reconnecting clients won't fall back to LP http.HandleFunc("/v0/channels", serveWebSocket) // Handle long polling clients http.HandleFunc("/v0/channels/lp", serveLongPoll) log.Printf("Listening on [%s]", config.Listen) if err := listenAndServe(config.Listen, signalHandler()); err != nil { log.Fatal(err) } log.Println("All done, good bye") }
func gen_rethink(reset bool, dbsource string, data *Data) { var err error log.Println("Opening DB...") err = store.Open("rethinkdb", dbsource) if err != nil { log.Fatal("Failed to connect to DB: ", err) } defer store.Close() log.Println("Initializing DB...") err = store.InitDb(reset) if err != nil { if strings.Contains(err.Error(), " already exists") { log.Println("DB already exists, NOT reinitializing") } else { log.Fatal("Failed to init DB: ", err) } } else { log.Println("DB successfully initialized") } if data.Users == nil { log.Println("No data provided, stopping") return } nameIndex := make(map[string]string, len(data.Users)) log.Println("Generating users...") for _, uu := range data.Users { if uu["createdAt"] != nil { } user := types.User{ State: int(uu["state"].(float64)), Username: uu["username"].(string), Access: types.DefaultAccess{ Auth: types.ModePublic, Anon: types.ModeNone, }, Public: uu["public"], } user.CreatedAt = getCreatedTime(uu["createdAt"]) // store.Users.Create will subscribe user to !me topic but won't create a !me topic if _, err := store.Users.Create(&user, "basic", uu["username"].(string)+":"+uu["passhash"].(string), uu["private"]); err != nil { log.Fatal(err) } nameIndex[user.Username] = user.Id log.Printf("Created user '%s' as %s (%d)", user.Username, user.Id, user.Uid()) } log.Println("Generating group topics...") for _, gt := range data.Grouptopics { name := genTopicName() nameIndex[gt["name"].(string)] = name topic := &types.Topic{Name: name, Public: gt["public"]} var owner types.Uid if gt["owner"] != nil { owner = types.ParseUid(nameIndex[gt["owner"].(string)]) topic.GiveAccess(owner, types.ModeFull, types.ModeFull) } topic.CreatedAt = getCreatedTime(gt["createdAt"]) if err = store.Topics.Create(topic, owner, gt["private"]); err != nil { log.Fatal(err) } log.Printf("Created topic '%s' as %s", gt["name"].(string), name) } log.Println("Generating P2P subscriptions...") p2pIndex := map[string][]map[string]interface{}{} for _, ss := range data.Subscriptions { u1 := ss["user"].(string) u2 := ss["topic"].(string) if u2[0] == '*' { // skip group topics continue } var pair string var idx int if u1 < u2 { pair = u1 + ":" + u2 idx = 0 } else { pair = u2 + ":" + u1 idx = 1 } if _, ok := p2pIndex[pair]; !ok { p2pIndex[pair] = make([]map[string]interface{}, 2) } p2pIndex[pair][idx] = ss } log.Printf("Collected p2p pairs: %d\n", len(p2pIndex)) for pair, subs := range p2pIndex { uid1 := types.ParseUid(nameIndex[subs[0]["user"].(string)]) uid2 := types.ParseUid(nameIndex[subs[1]["user"].(string)]) topic := uid1.P2PName(uid2) created0 := getCreatedTime(subs[0]["createdAt"]) created1 := getCreatedTime(subs[1]["createdAt"]) var s0want, s0given, s1want, s1given types.AccessMode if err := s0want.UnmarshalText([]byte(subs[0]["modeWant"].(string))); err != nil { log.Fatal(err) } if err := s0given.UnmarshalText([]byte(subs[0]["modeHave"].(string))); err != nil { log.Fatal(err) } if err := s1want.UnmarshalText([]byte(subs[1]["modeWant"].(string))); err != nil { log.Fatal(err) } if err := s1given.UnmarshalText([]byte(subs[1]["modeHave"].(string))); err != nil { log.Fatal(err) } log.Printf("Processing %s (%s), %s, %s", pair, topic, uid1.String(), uid2.String()) err := store.Topics.CreateP2P( &types.Subscription{ ObjHeader: types.ObjHeader{CreatedAt: created0}, User: uid1.String(), Topic: topic, ModeWant: s0want, ModeGiven: s0given, Private: subs[0]["private"]}, &types.Subscription{ ObjHeader: types.ObjHeader{CreatedAt: created1}, User: uid2.String(), Topic: topic, ModeWant: s1want, ModeGiven: s1given, Private: subs[1]["private"]}) if err != nil { log.Fatal(err) } } log.Println("Generating group subscriptions...") for _, ss := range data.Subscriptions { u1 := nameIndex[ss["user"].(string)] u2 := nameIndex[ss["topic"].(string)] var want, given types.AccessMode if err := want.UnmarshalText([]byte(ss["modeWant"].(string))); err != nil { log.Fatal(err) } if err := given.UnmarshalText([]byte(ss["modeHave"].(string))); err != nil { log.Fatal(err) } // Define topic name name := u2 if !types.ParseUid(u2).IsZero() { // skip p2p subscriptions continue } log.Printf("Sharing '%s' with '%s'", ss["topic"].(string), ss["user"].(string)) if err = store.Subs.Create(&types.Subscription{ ObjHeader: types.ObjHeader{CreatedAt: getCreatedTime(ss["createdAt"])}, User: u1, Topic: name, ModeWant: want, ModeGiven: given, Private: ss["private"]}); err != nil { log.Fatal(err) } } log.Println("Generating messages...") rand.Seed(time.Now().UnixNano()) seqIds := map[string]int{} var oldFrom types.Uid var oldTopic string toInsert := 80 // Starting 4 days ago timestamp := time.Now().UTC().Round(time.Millisecond).Add(time.Second * time.Duration(-3600*24*4)) for i := 0; i < toInsert; i++ { sub := data.Subscriptions[rand.Intn(len(data.Subscriptions))] topic := nameIndex[sub["topic"].(string)] from := types.ParseUid(nameIndex[sub["user"].(string)]) if topic == oldTopic && from == oldFrom { toInsert++ continue } oldTopic, oldFrom = topic, from if uid := types.ParseUid(topic); !uid.IsZero() { topic = uid.P2PName(from) } seqIds[topic]++ seqId := seqIds[topic] str := data.Messages[rand.Intn(len(data.Messages))] // Max time between messages is 2 hours, averate - 1 hour, time is increasing as seqId increases timestamp = timestamp.Add(time.Second * time.Duration(rand.Intn(3600*2))) msg := types.Message{ ObjHeader: types.ObjHeader{CreatedAt: timestamp}, SeqId: seqId, Topic: topic, From: from.String(), Content: str} if err = store.Messages.Save(&msg); err != nil { log.Fatal(err) } log.Printf("Message %d at %v to '%s' '%s'", msg.SeqId, msg.CreatedAt, topic, str) } }