func ProcessRescue(from Source, msgid uint32, req *proto.RescueRequest, t Transport) { a, err := models.FindAccount(models.DBM(), req.Account) if err != nil { SendError(from, msgid, &proto.Err{Type: proto.Error_Rescue_DatabaseError}) return } if !a.VerifySign(req.Sign, req.Walltime) { SendError(from, msgid, &proto.Err{Type: proto.Error_Rescue_InvalidAuth}) return } res, err := models.NewRescue(models.DBM(), req.Account) if err != nil { SendError(from, msgid, &proto.Err{Type: proto.Error_Rescue_DatabaseError}) return } //send post notification to all member in this Topic log.Printf("id:%v url:%v", req.Account, res.URL()) from.Send(&proto.Payload{ Type: proto.Payload_RescueResponse, Msgid: msgid, RescueResponse: &proto.RescueResponse{ Url: res.URL(), Remain: res.RemainTime(), }, }) }
func ProcessChannelCreate(from Source, msgid uint32, req *proto.ChannelCreateRequest, t Transport) { ch, err := models.NewChannel(models.DBM(), from.Account(), req) if err != nil { log.Printf("err: %v", err) SendError(from, msgid, err) return } //send post notification to all member in this Topic from.Send(&proto.Payload{ Type: proto.Payload_ChannelCreateResponse, Msgid: msgid, ChannelCreateResponse: &proto.ChannelCreateResponse{ Channel: &ch.Model_Channel, }, }) }
func ProcessChannelList(from Source, msgid uint32, req *proto.ChannelListRequest, t Transport) { chs, err := models.ListChannel(models.DBM(), req) if err != nil { log.Printf("err: %v", err) SendError(from, msgid, err) return } //send post notification to all member in this Topic from.Send(&proto.Payload{ Type: proto.Payload_ChannelListResponse, Msgid: msgid, ChannelListResponse: &proto.ChannelListResponse{ List: chs, }, }) }
func ProcessTopicCreate(from Source, msgid uint32, req *proto.TopicCreateRequest, t Transport) { tp, err := models.NewTopic(models.DBM(), from.Account(), req) if err != nil { log.Printf("err: %v", err) SendError(from, msgid, err) return } //send post notification to all member in this Topic from.Send(&proto.Payload{ Type: proto.Payload_TopicCreateResponse, Msgid: msgid, TopicCreateResponse: &proto.TopicCreateResponse{ Created: &tp.Model_Topic, }, }) }
func ProcessPostList(from Source, msgid uint32, req *proto.PostListRequest, t Transport) { ps, err := models.ListPost(models.DBM(), req) if err != nil { log.Printf("err: %v", err) SendError(from, msgid, err) return } from.Send(&proto.Payload{ Type: proto.Payload_PostListResponse, Msgid: msgid, PostListResponse: &proto.PostListResponse{ List: ps, }, }) }
func topicFetcher(btyp proto.TopicListRequest_BucketType, start, end time.Time, locale string) ([]FetchResult, error) { entries := make([]FetchResult, DEFAULT_HOTBUCKET_SIZE) dbm := models.DBM() var rows *sql.Rows var err error locale_clause := "" if len(locale) > 0 { locale_clause = fmt.Sprintf(" and locale = '%s'", locale) } switch btyp { case proto.TopicListRequest_Rising: where_clause := fmt.Sprintf("created >= %v and created < %v%s", yue.UUIDAt(start), yue.UUIDAt(end), locale_clause) rows, err = dbm.Query( dbm.Stmt( `select id,max(parent) as channel,sum(param) as point,count(persona) as vote from %s.reactions where %s and type = $1 group by id`, where_clause), proto.Model_Reaction_Topic_Vote) case proto.TopicListRequest_Hot: where_clause := fmt.Sprintf("id >= %v and id < %v%s", yue.UUIDAt(start), yue.UUIDAt(end), locale_clause) rows, err = dbm.Query( dbm.Stmt( `select id,channel,point,vote from %s.topics where %s order by point desc limit %v`, where_clause, len(entries))) case proto.TopicListRequest_Flame: /* u: upvote, d: downvote, v: vote, p: point u + d = v u - d = p u = (v + p) / 2 d = (v - p) / 2 u / v => (1 + p / v) / 2 abs(u / v - 0.5) = abs(p / (2 * v)) < threshold => abs(p / v) < 2 * threshold */ where_clause := fmt.Sprintf("id >= %v and id < %v%s", yue.UUIDAt(start), yue.UUIDAt(end), locale_clause) rows, err = dbm.Query( dbm.Stmt( `select id,channel,point,vote from %s.topics where %s and vote >= %v and abs(point / vote) < %v order by vote desc limit %v`, where_clause, FLAME_VOTE_THRESHOLD, FLAME_THRESHOLD*2, len(entries))) default: return nil, fmt.Errorf("invalid btyp: %v", btyp) } if err != nil { return nil, err } i := 0 for rows.Next() { if cap(entries) <= len(entries) { tmp := make([]FetchResult, 2*len(entries)) entries = append(tmp, entries...) } if err := rows.Scan(&entries[i].id, &entries[i].parent, &entries[i].score, &entries[i].vote); err != nil { return nil, err } i++ } return entries, nil }
func ProcessLogin(from Source, msgid uint32, req *proto.LoginRequest, t Transport) { user := req.User version := req.Version if AssetsConfig().App.ClientVersion != version { log.Printf("login user:%v client outdated %v:%v", user, AssetsConfig().App.ClientVersion, version) SendError(from, msgid, &proto.Err{Type: proto.Error_Login_OutdatedVersion}) return } rescue := req.Rescue if rescue != nil { a, err := models.FindRescueAccount(*rescue) if err != nil { SendError(from, msgid, &proto.Err{Type: proto.Error_Rescue_CannotRescue}) return } req.User = a.User req.Mail = a.Mail req.Id = &a.Id req.Pass = &a.Pass log.Printf("account %v rescue is enabled %v, force override secret", a.Id, *rescue) } walltime := req.Walltime //update account database a, created, err := models.NewAccount(models.DBM(), req.Id, proto.Model_Account_User, user, req.Mail) if err != nil { log.Printf("login create account database error: %v", err) SendError(from, msgid, &proto.Err{Type: proto.Error_Login_DatabaseError}) return } if pass := req.Pass; pass != nil { if !created { if *pass != a.Pass { SendError(from, msgid, &proto.Err{Type: proto.Error_Login_UserAlreadyExists}) return } } secret := a.ComputeSecret(*pass, walltime) a.Secret = secret a.Pass = *pass log.Printf("login database %v %v", a.User, a.Secret) if _, err := a.Save(models.DBM(), []string{"Secret", "Pass"}); err != nil { log.Printf("login update account database error: %v", err) SendError(from, msgid, &proto.Err{Type: proto.Error_Login_DatabaseError}) return } } else { if created { SendError(from, msgid, &proto.Err{Type: proto.Error_Login_UserNotFound}) return } sign := req.Sign log.Printf("sign:%v", *sign) if sign == nil || !a.VerifySign(*sign, walltime) { SendError(from, msgid, &proto.Err{Type: proto.Error_Login_InvalidAuth}) return } //TODO: with some duration, update hash } //set device information device_type := req.DeviceType device_id := req.DeviceId if device_id == nil { //TODO: get unique identifier of browser and use it as device_id. //(especially, if user uses mobile browser, how we identify it as same mobile device) tmp_device_id := "browser:" + a.StringId() tmp_device_type := "browser" device_id = &tmp_device_id device_type = &tmp_device_type } if _, _, err := models.NewDevice(models.DBM(), *device_id, *device_type, from.String(), a.Id); err != nil { log.Printf("register device fails %v:%v:%v:%v", *device_id, *device_type, a.Id, err) //continue } //compute response resp := &proto.LoginResponse{ Id: a.Id, Secret: a.Secret, } if rescue != nil { resp.Pass = req.Pass resp.Mail = &req.Mail resp.User = &req.User } //send post notification to all member in this Topic log.Printf("secret:%v, id:%v", a.Secret, a.Id) from.SetAccount(a) from.Send(&proto.Payload{ Type: proto.Payload_LoginResponse, Msgid: msgid, LoginResponse: resp, }) }