示例#1
0
文件: server.go 项目: dmorlo/grumble
// Allocate a new Murmur instance
func NewServer(id int64) (s *Server, err error) {
	s = new(Server)

	s.Id = id

	s.cfg = serverconf.New(nil)

	s.Users = make(map[uint32]*User)
	s.UserCertMap = make(map[string]*User)
	s.UserNameMap = make(map[string]*User)
	s.Users[0], err = NewUser(0, "SuperUser")
	s.UserNameMap["SuperUser"] = s.Users[0]
	s.nextUserId = 1

	s.Channels = make(map[int]*Channel)
	s.Channels[0] = NewChannel(0, "Root")
	s.nextChanId = 1

	s.Logger = log.New(&logtarget.Target, fmt.Sprintf("[%v] ", s.Id), log.LstdFlags|log.Lmicroseconds)

	return
}
示例#2
0
文件: freeze.go 项目: dmorlo/grumble
// Create a new server from its on-disk representation.
//
// This will read a full serialized server (typically stored in
// a file called 'main.fz') from disk.  It will also check for
// a log file ('log.fz') and iterate through the entries of the log
// file and apply the updates incrementally to the server.
//
// Once both the full server and the log file has been merged together
// in memory, a new full seralized server will be written and synced to
// disk, and the existing log file will be removed.
func NewServerFromFrozen(name string) (s *Server, err error) {
	id, err := strconv.ParseInt(name, 10, 64)
	if err != nil {
		return nil, err
	}

	path := filepath.Join(Args.DataDir, "servers", name)
	mainFile := filepath.Join(path, "main.fz")
	backupFile := filepath.Join(path, "backup.fz")
	logFn := filepath.Join(path, "log.fz")

	r, err := os.Open(mainFile)
	if os.IsNotExist(err) {
		err = os.Rename(backupFile, mainFile)
		if err != nil {
			return nil, err
		}
		r, err = os.Open(mainFile)
		if err != nil {
			return nil, err
		}
	} else if err != nil {
		return nil, err
	}
	defer r.Close()

	buf, err := ioutil.ReadAll(r)
	if err != nil {
		return nil, err
	}

	// Unmarshal the server from it's frozen state
	fs := freezer.Server{}
	err = proto.Unmarshal(buf, &fs)
	if err != nil {
		return nil, err
	}

	// Create a config map from the frozen server.
	cfgMap := map[string]string{}
	for _, cfgEntry := range fs.Config {
		if cfgEntry.Key != nil && cfgEntry.Value != nil {
			cfgMap[*cfgEntry.Key] = *cfgEntry.Value
		}
	}

	s, err = NewServer(id)
	if err != nil {
		return nil, err
	}
	s.cfg = serverconf.New(cfgMap)

	// Unfreeze the server's frozen bans.
	s.UnfreezeBanList(fs.BanList)

	// Add all channels, but don't hook up parent/child relationships
	// until after we've walked the log file. No need to make it harder
	// than it really is.
	parents := make(map[uint32]uint32)
	for _, fc := range fs.Channels {
		// The frozen channel must contain an Id and a Name,
		// since the server's frozen channels are guaranteed to
		// not be deltas.
		if fc.Id == nil || fc.Name == nil {
			continue
		}

		// Create the channel on the server.
		// Update the server's nextChanId field if it needs to be,
		// to make sure the server doesn't re-use channel id's.
		c := NewChannel(int(*fc.Id), *fc.Name)
		if c.Id >= s.nextChanId {
			s.nextChanId = c.Id + 1
		}

		// Update the channel with the contents of the freezer.Channel.
		c.Unfreeze(fc)

		// Add the channel's id to the server's channel-id-map.
		s.Channels[c.Id] = c

		// Mark the channel's parent
		if fc.ParentId != nil {
			parents[*fc.Id] = *fc.ParentId
		} else {
			delete(parents, *fc.Id)
		}
	}

	// Add all users
	for _, fu := range fs.Users {
		if fu.Id == nil && fu.Name == nil {
			continue
		}
		u, err := NewUser(*fu.Id, *fu.Name)
		if err != nil {
			return nil, err
		}
		if u.Id >= s.nextUserId {
			s.nextUserId = u.Id + 1
		}

		// Merge the contents of the freezer.User into
		// the user struct.
		u.Unfreeze(fu)

		// Update the server's user maps to point correctly
		// to the new user.
		s.Users[u.Id] = u
		s.UserNameMap[u.Name] = u
		if len(u.CertHash) > 0 {
			s.UserCertMap[u.CertHash] = u
		}
	}

	// Attempt to walk the stored log file
	logFile, err := os.Open(logFn)
	walker, err := freezer.NewReaderWalker(logFile)
	if err != nil {
		return nil, err
	}

	for {
		values, err := walker.Next()
		if err == io.EOF {
			err = logFile.Close()
			if err != nil {
				return nil, err
			}
			break
		} else if err != nil {
			return nil, err
		}

		for _, val := range values {
			switch val.(type) {
			case *freezer.User:
				fu := val.(*freezer.User)
				// Check if it's a valid freezer.User message. It must at least
				// have the Id field filled out for us to be able to do anything
				// with it. Warn the admin if an illegal entry is encountered.
				if fu.Id == nil {
					log.Printf("Skipped User log entry: No id given.")
					continue
				}

				userId := *fu.Id

				// Determine whether the user already exists on the server or not.
				// If the user already exists, this log entry simply updates the
				// data for that user.
				// If the user doesn't exist, we create it with the data given in
				// this log entry.
				user, ok := s.Users[userId]
				if !ok {
					// If no name is given in the log entry, skip this entry.
					// Also, warn the admin.
					if fu.Name == nil {
						log.Printf("Skipped User creation log entry: No name given.")
						continue
					}
					// Create the new user and increment the UserId
					// counter for the server if needed.
					user, err = NewUser(userId, *fu.Name)
					if err != nil {
						return nil, err
					}
					if user.Id >= s.nextUserId {
						s.nextUserId = user.Id + 1
					}
				}

				// Merge the contents of the frozen.User into the
				// user struct.
				user.Unfreeze(fu)

				// Update the various user maps in the server to
				// be able to correctly look up the user.
				s.Users[user.Id] = user
				s.UserNameMap[user.Name] = user
				if len(user.CertHash) > 0 {
					s.UserCertMap[user.CertHash] = user
				}

			case *freezer.UserRemove:
				fu := val.(*freezer.UserRemove)
				// Check for an invalid message and warn if appropriate.
				if fu.Id == nil {
					log.Printf("Skipped UserRemove log entry: No id given.")
					continue
				}

				userId := *fu.Id

				// Does this user even exist?
				// Warn if we encounter an illegal delete op.
				user, ok := s.Users[userId]
				if ok {
					// Clear the server maps. That should do it.
					delete(s.Users, userId)
					delete(s.UserNameMap, user.Name)
					if len(user.CertHash) > 0 {
						delete(s.UserCertMap, user.CertHash)
					}
				} else {
					log.Printf("Skipped UserRemove log entry: No user for given id.")
					continue
				}

			case *freezer.Channel:
				fc := val.(*freezer.Channel)
				// Check whether the log entry is legal.
				if fc.Id == nil {
					log.Printf("Skipped Channel log entry: No id given.")
					continue
				}

				channelId := int(*fc.Id)

				channel, alreadyExists := s.Channels[channelId]
				if !alreadyExists {
					if fc.Name == nil {
						log.Printf("Skipped Channel creation log entry: No name given.")
						continue
					}
					// Add the channel and increment the server's
					// nextChanId field to a consistent state.
					channel = NewChannel(channelId, *fc.Name)
					if channel.Id >= s.nextChanId {
						s.nextChanId = channel.Id + 1
					}
				}

				// Unfreeze the contents of the frozen channel
				// into the existing or newly-created channel.
				channel.Unfreeze(fc)
				// Re-add it to the server's channel map (in case
				// the channel was newly-created)
				s.Channels[channelId] = channel

				// Mark the channel's parent
				if !alreadyExists {
					if fc.ParentId != nil {
						parents[*fc.Id] = *fc.ParentId
					} else {
						delete(parents, *fc.Id)
					}
				}

			case *freezer.ChannelRemove:
				fc := val.(*freezer.ChannelRemove)
				if fc.Id == nil {
					log.Printf("Skipped ChannelRemove log entry: No id given.")
					continue
				}
				s.Channels[int(*fc.Id)] = nil
				delete(parents, *fc.Id)

			case *freezer.BanList:
				fbl := val.(*freezer.BanList)
				s.UnfreezeBanList(fbl)

			case *freezer.ConfigKeyValuePair:
				fcfg := val.(*freezer.ConfigKeyValuePair)
				if fcfg.Key != nil {
					// It's an update operation
					if fcfg.Value != nil {
						s.cfg.Set(*fcfg.Key, *fcfg.Value)
						// It's a delete/reset operation.
					} else {
						s.cfg.Reset(*fcfg.Key)
					}
				}
			}
		}
	}

	// Hook up children with their parents
	for chanId, parentId := range parents {
		childChan, exists := s.Channels[int(chanId)]
		if !exists {
			return nil, errors.New("Non-existant child channel")
		}
		parentChan, exists := s.Channels[int(parentId)]
		if !exists {
			return nil, errors.New("Non-existant parent channel")
		}
		parentChan.AddChild(childChan)
	}

	// Hook up all channel links
	for _, channel := range s.Channels {
		if len(channel.Links) > 0 {
			links := channel.Links
			channel.Links = make(map[int]*Channel)
			for chanId, _ := range links {
				targetChannel := s.Channels[chanId]
				if targetChannel != nil {
					s.LinkChannels(channel, targetChannel)
				}
			}
		}
	}

	return s, nil
}